| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Geo::Forward; |
|
2
|
3
|
|
|
3
|
|
436656
|
use strict; |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
143
|
|
|
3
|
3
|
|
|
3
|
|
20
|
use warnings; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
136
|
|
|
4
|
3
|
|
|
3
|
|
26
|
use base qw{Package::New}; |
|
|
3
|
|
|
|
|
11
|
|
|
|
3
|
|
|
|
|
3647
|
|
|
5
|
3
|
|
|
3
|
|
3163
|
use Geo::Constants 0.04 qw{PI}; |
|
|
3
|
|
|
|
|
836
|
|
|
|
3
|
|
|
|
|
209
|
|
|
6
|
3
|
|
|
3
|
|
1490
|
use Geo::Functions 0.03 qw{deg_rad rad_deg}; |
|
|
3
|
|
|
|
|
1859
|
|
|
|
3
|
|
|
|
|
196
|
|
|
7
|
3
|
|
|
3
|
|
2468
|
use Geo::Ellipsoids 0.09 qw{}; |
|
|
3
|
|
|
|
|
6405
|
|
|
|
3
|
|
|
|
|
2207
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION="0.14"; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Geo::Forward - Calculate geographic location from lat, lon, distance, and heading. |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
use Geo::Forward; |
|
18
|
|
|
|
|
|
|
my $obj = Geo::Forward->new(); # default "WGS84" |
|
19
|
|
|
|
|
|
|
my ($lat1,$lon1,$faz,$dist)=(38.871022, -77.055874, 62.888507083, 4565.6854); |
|
20
|
|
|
|
|
|
|
my ($lat2,$lon2,$baz) = $obj->forward($lat1,$lon1,$faz,$dist); |
|
21
|
|
|
|
|
|
|
print "Input Lat: $lat1 Lon: $lon1\n"; |
|
22
|
|
|
|
|
|
|
print "Input Forward Azimuth: $faz\n"; |
|
23
|
|
|
|
|
|
|
print "Input Distance: $dist\n"; |
|
24
|
|
|
|
|
|
|
print "Output Lat: $lat2 Lon: $lon2\n"; |
|
25
|
|
|
|
|
|
|
print "Output Back Azimuth: $baz\n"; |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
This module is a pure Perl port of the NGS program in the public domain "forward" by Robert (Sid) Safford and Stephen J. Frakes. |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head2 new |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
The new() constructor may be called with any parameter that is appropriate to the ellipsoid method which establishes the ellipsoid. |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
my $obj = Geo::Forward->new(); # default "WGS84" |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 METHODS |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head2 initialize |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=cut |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub initialize { |
|
46
|
3
|
|
|
3
|
1
|
59
|
my $self = shift; |
|
47
|
3
|
|
50
|
|
|
19
|
my $param = shift || undef; |
|
48
|
3
|
|
|
|
|
14
|
$self->ellipsoid($param); |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head2 ellipsoid |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
Method to set or retrieve the current ellipsoid object. The ellipsoid is a L object. |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
my $ellipsoid=$obj->ellipsoid; #Default is WGS84 |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
$obj->ellipsoid('Clarke 1866'); #Built in ellipsoids from Geo::Ellipsoids |
|
58
|
|
|
|
|
|
|
$obj->ellipsoid({a=>1}); #Custom Sphere 1 unit radius |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=cut |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub ellipsoid { |
|
63
|
1012
|
|
|
1012
|
1
|
2693
|
my $self=shift; |
|
64
|
1012
|
100
|
|
|
|
2370
|
if (@_) { |
|
65
|
3
|
|
|
|
|
4
|
my $param=shift; |
|
66
|
3
|
|
|
|
|
19
|
$self->{'ellipsoid'}=Geo::Ellipsoids->new($param); |
|
67
|
|
|
|
|
|
|
} |
|
68
|
1012
|
|
|
|
|
2484
|
return $self->{'ellipsoid'}; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head2 forward |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
This method is the user frontend to the mathematics. This interface will not change in future versions. |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
my ($lat2,$lon2,$baz) = $obj->forward($lat1,$lon1,$faz,$dist); |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Note: Latitude and longitude units are signed decimal degrees. The distance units are based on the ellipsoid semi-major axis which is meters for WGS-84. The forward and backward azimuths units are signed degrees clockwise from North. |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=cut |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub forward { |
|
82
|
1007
|
|
|
1007
|
1
|
701974
|
my $self = shift; |
|
83
|
1007
|
|
|
|
|
1292
|
my $lat = shift; #degrees |
|
84
|
1007
|
|
|
|
|
1011
|
my $lon = shift; #degrees |
|
85
|
1007
|
|
|
|
|
990
|
my $heading = shift; #degrees |
|
86
|
1007
|
|
|
|
|
941
|
my $distance = shift; #meters (or the units of the semi-major axis) |
|
87
|
1007
|
|
|
|
|
2444
|
my ($lat2, $lon2, $baz)= $self->_dirct1(rad_deg($lat),rad_deg($lon),rad_deg($heading),$distance); |
|
88
|
1007
|
|
|
|
|
2814
|
return(deg_rad($lat2), deg_rad($lon2), deg_rad($baz)); |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub _dirct1 { |
|
92
|
1007
|
|
|
1007
|
|
18094
|
my $self = shift; #provides A and F |
|
93
|
1007
|
|
|
|
|
1216
|
my $GLAT1 = shift; #radians |
|
94
|
1007
|
|
|
|
|
972
|
my $GLON1 = shift; #radians |
|
95
|
1007
|
|
|
|
|
938
|
my $FAZ = shift; #radians |
|
96
|
1007
|
|
|
|
|
1022
|
my $S = shift; #units of semi-major axis (default meters) |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# SUBROUTINE DIRCT1(GLAT1,GLON1,GLAT2,GLON2,FAZ,BAZ,S) |
|
99
|
|
|
|
|
|
|
#C |
|
100
|
|
|
|
|
|
|
#C *** SOLUTION OF THE GEODETIC DIRECT PROBLEM AFTER T.VINCENTY |
|
101
|
|
|
|
|
|
|
#C *** MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS |
|
102
|
|
|
|
|
|
|
#C *** EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL |
|
103
|
|
|
|
|
|
|
#C |
|
104
|
|
|
|
|
|
|
#C *** A IS THE SEMI-MAJOR AXIS OF THE REFERENCE ELLIPSOID |
|
105
|
|
|
|
|
|
|
#C *** F IS THE FLATTENING OF THE REFERENCE ELLIPSOID |
|
106
|
|
|
|
|
|
|
#C *** LATITUDES AND LONGITUDES IN RADIANS POSITIVE NORTH AND EAST |
|
107
|
|
|
|
|
|
|
#C *** AZIMUTHS IN RADIANS CLOCKWISE FROM NORTH |
|
108
|
|
|
|
|
|
|
#C *** GEODESIC DISTANCE S ASSUMED IN UNITS OF SEMI-MAJOR AXIS A |
|
109
|
|
|
|
|
|
|
#C |
|
110
|
|
|
|
|
|
|
#C *** PROGRAMMED FOR CDC-6600 BY LCDR L.PFEIFER NGS ROCKVILLE MD 20FEB75 |
|
111
|
|
|
|
|
|
|
#C *** MODIFIED FOR SYSTEM 360 BY JOHN G GERGEN NGS ROCKVILLE MD 750608 |
|
112
|
|
|
|
|
|
|
#C |
|
113
|
|
|
|
|
|
|
# IMPLICIT REAL*8 (A-H,O-Z) |
|
114
|
|
|
|
|
|
|
# COMMON/CONST/PI,RAD |
|
115
|
|
|
|
|
|
|
# COMMON/ELIPSOID/A,F |
|
116
|
1007
|
|
|
|
|
1833
|
my $ellipsoid=$self->ellipsoid; |
|
117
|
1007
|
|
|
|
|
2691
|
my $A=$ellipsoid->a; |
|
118
|
1007
|
|
|
|
|
5322
|
my $F=$ellipsoid->f; |
|
119
|
|
|
|
|
|
|
# DATA EPS/0.5D-13/ |
|
120
|
1007
|
|
|
|
|
6368
|
my $EPS=0.5E-13; |
|
121
|
|
|
|
|
|
|
# R=1.-F |
|
122
|
1007
|
|
|
|
|
1299
|
my $R=1.-$F; |
|
123
|
|
|
|
|
|
|
# TU=R*DSIN(GLAT1)/DCOS(GLAT1) |
|
124
|
1007
|
|
|
|
|
2080
|
my $TU=$R*sin($GLAT1)/cos($GLAT1); |
|
125
|
|
|
|
|
|
|
# SF=DSIN(FAZ) |
|
126
|
1007
|
|
|
|
|
1378
|
my $SF=sin($FAZ); |
|
127
|
|
|
|
|
|
|
# CF=DCOS(FAZ) |
|
128
|
1007
|
|
|
|
|
1170
|
my $CF=cos($FAZ); |
|
129
|
|
|
|
|
|
|
# BAZ=0. |
|
130
|
1007
|
|
|
|
|
989
|
my $BAZ=0.; |
|
131
|
|
|
|
|
|
|
# IF(CF.NE.0.) BAZ=DATAN2(TU,CF)*2. |
|
132
|
1007
|
50
|
|
|
|
3337
|
$BAZ=atan2($TU,$CF)*2. if ($CF != 0); |
|
133
|
|
|
|
|
|
|
# CU=1./DSQRT(TU*TU+1.) |
|
134
|
1007
|
|
|
|
|
1763
|
my $CU=1./sqrt($TU*$TU+1.); |
|
135
|
|
|
|
|
|
|
# SU=TU*CU |
|
136
|
1007
|
|
|
|
|
1173
|
my $SU=$TU*$CU; |
|
137
|
|
|
|
|
|
|
# SA=CU*SF |
|
138
|
1007
|
|
|
|
|
1103
|
my $SA=$CU*$SF; |
|
139
|
|
|
|
|
|
|
# C2A=-SA*SA+1. |
|
140
|
1007
|
|
|
|
|
1535
|
my $C2A=-$SA*$SA+1.; |
|
141
|
|
|
|
|
|
|
# X=DSQRT((1./R/R-1.)*C2A+1.)+1. |
|
142
|
1007
|
|
|
|
|
1924
|
my $X=sqrt((1./$R/$R-1.)*$C2A+1.)+1.; |
|
143
|
|
|
|
|
|
|
# X=(X-2.)/X |
|
144
|
1007
|
|
|
|
|
1504
|
$X=($X-2.)/$X; |
|
145
|
|
|
|
|
|
|
# C=1.-X |
|
146
|
1007
|
|
|
|
|
1253
|
my $C=1.-$X; |
|
147
|
|
|
|
|
|
|
# C=(X*X/4.+1)/C |
|
148
|
1007
|
|
|
|
|
1328
|
$C=($X*$X/4.+1)/$C; |
|
149
|
|
|
|
|
|
|
# D=(0.375D0*X*X-1.)*X |
|
150
|
1007
|
|
|
|
|
1525
|
my $D=(0.375*$X*$X-1.)*$X; |
|
151
|
|
|
|
|
|
|
# TU=S/R/A/C |
|
152
|
1007
|
|
|
|
|
1381
|
$TU=$S/$R/$A/$C; |
|
153
|
|
|
|
|
|
|
# Y=TU |
|
154
|
1007
|
|
|
|
|
1017
|
my $Y=$TU; |
|
155
|
|
|
|
|
|
|
# 100 SY=DSIN(Y) |
|
156
|
1007
|
|
|
|
|
1075
|
my ($SY, $CY, $CZ, $E); |
|
157
|
1007
|
|
|
|
|
956
|
do{ $SY=sin($Y); |
|
|
1020
|
|
|
|
|
1224
|
|
|
158
|
|
|
|
|
|
|
# CY=DCOS(Y) |
|
159
|
1020
|
|
|
|
|
988
|
$CY=cos($Y); |
|
160
|
|
|
|
|
|
|
# CZ=DCOS(BAZ+Y) |
|
161
|
1020
|
|
|
|
|
1471
|
$CZ=cos($BAZ+$Y); |
|
162
|
|
|
|
|
|
|
# E=CZ*CZ*2.-1. |
|
163
|
1020
|
|
|
|
|
1273
|
$E=$CZ*$CZ*2.-1.; |
|
164
|
|
|
|
|
|
|
# C=Y |
|
165
|
1020
|
|
|
|
|
1055
|
$C=$Y; |
|
166
|
|
|
|
|
|
|
# X=E*CY |
|
167
|
1020
|
|
|
|
|
1194
|
$X=$E*$CY; |
|
168
|
|
|
|
|
|
|
# Y=E+E-1. |
|
169
|
1020
|
|
|
|
|
1059
|
$Y=$E+$E-1.; |
|
170
|
|
|
|
|
|
|
# Y=(((SY*SY*4.-3.)*Y*CZ*D/6.+X)*D/4.-CZ)*SY*D+TU |
|
171
|
1020
|
|
|
|
|
4447
|
$Y=((($SY*$SY*4.-3.)*$Y*$CZ*$D/6.+$X)*$D/4.-$CZ)*$SY*$D+$TU; |
|
172
|
|
|
|
|
|
|
# IF(DABS(Y-C).GT.EPS)GO TO 100 |
|
173
|
|
|
|
|
|
|
} while (abs($Y-$C) > $EPS); |
|
174
|
|
|
|
|
|
|
# BAZ=CU*CY*CF-SU*SY |
|
175
|
1007
|
|
|
|
|
1449
|
$BAZ=$CU*$CY*$CF-$SU*$SY; |
|
176
|
|
|
|
|
|
|
# C=R*DSQRT(SA*SA+BAZ*BAZ) |
|
177
|
1007
|
|
|
|
|
1352
|
$C=$R*sqrt($SA*$SA+$BAZ*$BAZ); |
|
178
|
|
|
|
|
|
|
# D=SU*CY+CU*SY*CF |
|
179
|
1007
|
|
|
|
|
1356
|
$D=$SU*$CY+$CU*$SY*$CF; |
|
180
|
|
|
|
|
|
|
# GLAT2=DATAN2(D,C) |
|
181
|
1007
|
|
|
|
|
1657
|
my $GLAT2=atan2($D,$C); |
|
182
|
|
|
|
|
|
|
# C=CU*CY-SU*SY*CF |
|
183
|
1007
|
|
|
|
|
1337
|
$C=$CU*$CY-$SU*$SY*$CF; |
|
184
|
|
|
|
|
|
|
# X=DATAN2(SY*SF,C) |
|
185
|
1007
|
|
|
|
|
1155
|
$X=atan2($SY*$SF,$C); |
|
186
|
|
|
|
|
|
|
# C=((-3.*C2A+4.)*F+4.)*C2A*F/16. |
|
187
|
1007
|
|
|
|
|
1551
|
$C=((-3.*$C2A+4.)*$F+4.)*$C2A*$F/16.; |
|
188
|
|
|
|
|
|
|
# D=((E*CY*C+CZ)*SY*C+Y)*SA |
|
189
|
1007
|
|
|
|
|
1625
|
$D=(($E*$CY*$C+$CZ)*$SY*$C+$Y)*$SA; |
|
190
|
|
|
|
|
|
|
# GLON2=GLON1+X-(1.-C)*D*F |
|
191
|
1007
|
|
|
|
|
1668
|
my $GLON2=$GLON1+$X-(1.-$C)*$D*$F; |
|
192
|
|
|
|
|
|
|
# BAZ=DATAN2(SA,BAZ)+PI |
|
193
|
1007
|
|
|
|
|
2731
|
$BAZ=atan2($SA,$BAZ)+PI; |
|
194
|
|
|
|
|
|
|
# RETURN |
|
195
|
1007
|
|
|
|
|
4574
|
return $GLAT2, $GLON2, $BAZ; |
|
196
|
|
|
|
|
|
|
# END |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=head1 TODO |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
Add tests for more ellipsoids. |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=head1 BUGS |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
Please log on RT and email to the geo-perl email list as well as the author. |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head1 SUPPORT |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
DavisNetworks.com supports all Perl applications including this package. |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head1 LIMITS |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
No guarantees that Perl handles all of the double precision calculations in the same manner as Fortran. |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head1 AUTHOR |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
Michael R. Davis qw/perl michaelrdavis com/ |
|
218
|
|
|
|
|
|
|
CPAN ID: MRDVT |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=head1 LICENSE |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Copyright (c) 2011 Michael R. Davis (mrdvt92) |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head3 Similar Packages |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
L, L |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=head2 Opposite Packages |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
L |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=head2 Building Blocks |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
L, L, L |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=cut |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
1; |