line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Geo::ECEF; |
2
|
1
|
|
|
1
|
|
920
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
59
|
|
3
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
4
|
1
|
|
|
1
|
|
1112
|
use Geo::Ellipsoids; |
|
1
|
|
|
|
|
6055
|
|
|
1
|
|
|
|
|
47
|
|
5
|
1
|
|
|
1
|
|
14
|
use Geo::Functions qw{rad_deg deg_rad}; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
280
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION="1.10"; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Geo::ECEF - Converts between ECEF (earth centered earth fixed) coordinates and latitude, longitude and height above ellipsoid. |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 SYNOPSIS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
use Geo::ECEF; |
16
|
|
|
|
|
|
|
my $obj=Geo::ECEF->new(); #WGS84 is the default |
17
|
|
|
|
|
|
|
my ($x, $y, $z)=$obj->ecef(39.197807, -77.108574, 55); #Lat (deg), Lon (deg), HAE (meters) |
18
|
|
|
|
|
|
|
print "X: $x\tY: $y\tZ: $z\n"; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
my ($lat, $lon, $hae)=$obj->geodetic($x, $y, $z); #X (meters), Y (meters), Z (meters) |
21
|
|
|
|
|
|
|
print "Lat: $lat \tLon: $lon \tHAE $hae\n"; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 DESCRIPTION |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
Geo::ECEF provides two methods ecef and geodetic. The ecef method calculates the X,Y and Z coordinates in the ECEF (earth centered earth fixed) coordinate system from latitude, longitude and height above the ellipsoid. The geodetic method calculates the latitude, longitude and height above ellipsoid from ECEF coordinates. |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
The formulas were found at http://www.u-blox.ch/ and http://waas.stanford.edu/~wwu/maast/maastWWW1_0.zip. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
This code is an object Perl rewrite of a similar package by Morten Sickel, Norwegian Radiation Protection Authority |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head2 new |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
The new() constructor initializes the ellipsoid method. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my $obj=Geo::ECEF->new("WGS84"); #WGS84 is the default |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=cut |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub new { |
43
|
1
|
|
|
1
|
1
|
576
|
my $this = shift(); |
44
|
1
|
|
33
|
|
|
11
|
my $class = ref($this) || $this; |
45
|
1
|
|
|
|
|
3
|
my $self = {}; |
46
|
1
|
|
|
|
|
2
|
bless $self, $class; |
47
|
1
|
|
|
|
|
4
|
$self->initialize(@_); |
48
|
1
|
|
|
|
|
3
|
return $self; |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head1 METHODS |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head2 initialize |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=cut |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub initialize { |
58
|
2
|
|
|
2
|
1
|
559
|
my $self = shift(); |
59
|
2
|
|
100
|
|
|
11
|
my $param = shift()||undef(); |
60
|
2
|
|
|
|
|
5
|
$self->ellipsoid($param); |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head2 ellipsoid |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
Method to set or retrieve the current ellipsoid object. The ellipsoid is a Geo::Ellipsoids object. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
my $ellipsoid=$obj->ellipsoid; #Default is WGS84 |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
$obj->ellipsoid('Clarke 1866'); #Built in ellipsoids from Geo::Ellipsoids |
70
|
|
|
|
|
|
|
$obj->ellipsoid({a=>1}); #Custom Sphere 1 unit radius |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub ellipsoid { |
75
|
27
|
|
|
27
|
1
|
32
|
my $self = shift(); |
76
|
27
|
100
|
|
|
|
57
|
if (@_) { |
77
|
2
|
|
|
|
|
3
|
my $param=shift(); |
78
|
1
|
|
|
1
|
|
19
|
use Geo::Ellipsoids; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
969
|
|
79
|
2
|
|
|
|
|
11
|
my $obj=Geo::Ellipsoids->new($param); |
80
|
2
|
|
|
|
|
576
|
$self->{'ellipsoid'}=$obj; |
81
|
|
|
|
|
|
|
} |
82
|
27
|
|
|
|
|
65
|
return $self->{'ellipsoid'}; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head2 ecef |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Method returns X (meters), Y (meters), Z (meters) from lat (degrees), lon (degrees), HAE (meters). |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
my ($x, $y, $z)=$obj->ecef(39.197807, -77.108574, 55); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=cut |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub ecef { |
94
|
15
|
|
|
15
|
1
|
6082
|
my $self = shift(); |
95
|
15
|
|
100
|
|
|
68
|
my $lat_rad=rad_deg(shift()||0); |
96
|
15
|
|
100
|
|
|
186
|
my $lon_rad=rad_deg(shift()||0); |
97
|
15
|
|
100
|
|
|
143
|
my $hae=shift()||0; |
98
|
15
|
|
|
|
|
35
|
return $self->ecef_rad($lat_rad, $lon_rad, $hae); |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head2 ecef_rad |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Method returns X (meters), Y (meters), Z (meters) from lat (radians), lon (radians), HAE (meters). |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
my ($x, $y, $z)=$obj->ecef(0.678, -0.234, 55); |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
This method may be copyright Michael Kleder, April 2006 from mathworks.com |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=cut |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub ecef_rad { |
112
|
15
|
|
|
15
|
1
|
17
|
my $self = shift(); |
113
|
15
|
|
100
|
|
|
38
|
my $lat=shift()||0; |
114
|
15
|
|
100
|
|
|
45
|
my $lon=shift()||0; |
115
|
15
|
|
100
|
|
|
43
|
my $hae=shift()||0; |
116
|
15
|
|
|
|
|
28
|
my $ellipsoid=$self->ellipsoid; |
117
|
15
|
|
|
|
|
43
|
my $e2=$ellipsoid->e2; |
118
|
15
|
|
|
|
|
174
|
my $n=$ellipsoid->n_rad($lat); |
119
|
15
|
|
|
|
|
359
|
my $x=($n+$hae) * cos($lat) * cos($lon); |
120
|
15
|
|
|
|
|
35
|
my $y=($n+$hae) * cos($lat) * sin($lon); |
121
|
15
|
|
|
|
|
29
|
my $z=((1-$e2) * $n + $hae) * sin($lat); |
122
|
15
|
|
|
|
|
34
|
my @array=($x, $y, $z); |
123
|
15
|
100
|
|
|
|
84
|
return wantarray ? @array : \@array; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=head2 geodetic |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
Calls the default geodetic method. This user interface will not change, |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Method returns latitude (degrees), longitude (degrees), HAE (meters) from X (meters), Y (meters), Z (meters). |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
my ($lat, $lon, $hae)=$obj->geodetic($x, $y, $z); |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=cut |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub geodetic { |
137
|
6
|
|
|
6
|
1
|
3886
|
my $self = shift(); |
138
|
6
|
|
|
|
|
18
|
return $self->geodetic_direct(@_); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head2 geodetic_iterative |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
Method returns latitude (degrees), longitude (degrees), HAE (meters) from X (meters), Y (meters), Z (meters). This is an iterative calculation. |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
my ($lat, $lon, $hae)=$obj->geodetic($x, $y, $z); |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Portions of this method may be... |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
************************************************************************* |
150
|
|
|
|
|
|
|
* Copyright c 2001 The board of trustees of the Leland Stanford * |
151
|
|
|
|
|
|
|
* Junior University. All rights reserved. * |
152
|
|
|
|
|
|
|
* This script file may be distributed and used freely, provided * |
153
|
|
|
|
|
|
|
* this copyright notice is always kept with it. * |
154
|
|
|
|
|
|
|
* * |
155
|
|
|
|
|
|
|
* Questions and comments should be directed to Todd Walter at: * |
156
|
|
|
|
|
|
|
* twalter@stanford.edu * |
157
|
|
|
|
|
|
|
************************************************************************* |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=cut |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub geodetic_iterative { |
162
|
0
|
|
|
0
|
1
|
0
|
my $self = shift(); |
163
|
0
|
|
0
|
|
|
0
|
my $x=shift()||0; |
164
|
0
|
|
0
|
|
|
0
|
my $y=shift()||0; |
165
|
0
|
|
0
|
|
|
0
|
my $z=shift()||0; |
166
|
0
|
|
|
|
|
0
|
my $ellipsoid=$self->ellipsoid; |
167
|
0
|
|
|
|
|
0
|
my $e2=$ellipsoid->e2; |
168
|
0
|
|
|
|
|
0
|
my $p=sqrt($x**2 + $y**2); |
169
|
0
|
|
|
|
|
0
|
my $lon=atan2($y,$x); |
170
|
0
|
|
|
|
|
0
|
my $lat=atan2($z/$p, 0.01); |
171
|
0
|
|
|
|
|
0
|
my $n=$ellipsoid->n_rad($lat); |
172
|
0
|
|
|
|
|
0
|
my $hae=$p/cos($lat) - $n; |
173
|
0
|
|
|
|
|
0
|
my $old_hae=-1e-9; |
174
|
0
|
|
|
|
|
0
|
my $num=$z/$p; |
175
|
0
|
|
|
|
|
0
|
while (abs($hae-$old_hae) > 1e-4) { |
176
|
0
|
|
|
|
|
0
|
$old_hae=$hae; |
177
|
0
|
|
|
|
|
0
|
my $den=1 - $e2 * $n /($n + $hae); |
178
|
0
|
|
|
|
|
0
|
$lat=atan2($num, $den); |
179
|
0
|
|
|
|
|
0
|
$n=$ellipsoid->n_rad($lat); |
180
|
0
|
|
|
|
|
0
|
$hae=$p/cos($lat)-$n; |
181
|
|
|
|
|
|
|
} |
182
|
0
|
|
|
|
|
0
|
$lat=deg_rad($lat); |
183
|
0
|
|
|
|
|
0
|
$lon=deg_rad($lon); |
184
|
0
|
|
|
|
|
0
|
my @array=($lat, $lon, $hae); |
185
|
0
|
0
|
|
|
|
0
|
return wantarray ? @array : \@array; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head2 geodetic_direct |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
Method returns latitude (degrees), longitude (degrees), HAE (meters) from X (meters), Y (meters), Z (meters). This is a direct (non-iterative) calculation from the gpsd distribution. |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
my ($lat, $lon, $hae)=$obj->geodetic($x, $y, $z); |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
This method may be copyright Michael Kleder, April 2006 from mathworks.com |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=cut |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub geodetic_direct { |
199
|
10
|
|
|
10
|
1
|
1238
|
my $self = shift(); |
200
|
10
|
|
50
|
|
|
25
|
my $x=shift()||0; |
201
|
10
|
|
100
|
|
|
28
|
my $y=shift()||0; |
202
|
10
|
|
50
|
|
|
20
|
my $z=shift()||0; |
203
|
|
|
|
|
|
|
|
204
|
10
|
|
|
|
|
23
|
my $ellipsoid=$self->ellipsoid; |
205
|
10
|
|
|
|
|
32
|
my $a = $ellipsoid->a; |
206
|
10
|
|
|
|
|
58
|
my $b = $ellipsoid->b; |
207
|
10
|
|
|
|
|
93
|
my $e2 = $ellipsoid->e2; |
208
|
10
|
|
|
|
|
96
|
my $ep2 = $ellipsoid->ep2; |
209
|
10
|
|
|
|
|
151
|
my $p = sqrt($x**2 + $y**2); |
210
|
10
|
|
|
|
|
34
|
my $t = atan2($z*$a, $p*$b); |
211
|
10
|
|
|
|
|
22
|
my $lon=atan2($y, $x); |
212
|
10
|
|
|
|
|
61
|
my $lat=atan2($z + $ep2*$b*sin($t)**3, $p - $e2*$a*cos($t)**3); |
213
|
10
|
|
|
|
|
30
|
my $n = $ellipsoid->n_rad($lat); |
214
|
10
|
|
|
|
|
159
|
my $hae; |
215
|
10
|
|
|
|
|
15
|
eval { |
216
|
10
|
|
|
|
|
21
|
$hae = $p/cos($lat) - $n; #Just in case $lat is +-90 degrees |
217
|
|
|
|
|
|
|
}; |
218
|
|
|
|
|
|
|
|
219
|
10
|
|
|
|
|
11
|
my @array; |
220
|
10
|
50
|
|
|
|
18
|
if ($@) { |
221
|
0
|
|
|
|
|
0
|
@array=(deg_rad($lat), 0, abs($z)-$b); #Is this correct? |
222
|
|
|
|
|
|
|
} else { |
223
|
10
|
|
|
|
|
53
|
@array=(deg_rad($lat), deg_rad($lon), $hae); |
224
|
|
|
|
|
|
|
} |
225
|
10
|
100
|
|
|
|
171
|
return wantarray ? @array : \@array; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head1 TODO |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head1 SUPPORT |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
DavisNetworks.com supports all Perl applications big or small. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=head1 BUGS |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Please log on RT and send email to the geo-perl email list. |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=head1 LIMITS |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Win32 platforms cannot tell the difference between the deprecated L module and the current L module. The way to tell is if Geo::ECEF->can("new"); |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=head1 AUTHORS |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
Michael R. Davis qw/perl michaelrdavis com/ |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
Morten Sickel http://sickel.net/ |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=head1 LICENSE |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
Copyright (c) 2007-2010 Michael R. Davis (mrdvt92) |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Copyright (c) 2005 Morten Sickel (sickel.net) |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=head1 SEE ALSO |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
L, L, L, L, L, http://www.ngs.noaa.gov/cgi-bin/xyz_getxyz.prl, http://www.mathworks.com/matlabcentral/ |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=cut |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
1; |