File Coverage

blib/lib/Geo/Coordinates/ITM.pm
Criterion Covered Total %
statement 99 99 100.0
branch n/a
condition n/a
subroutine 13 13 100.0
pod 2 2 100.0
total 114 114 100.0


line stmt bran cond sub pod time code
1             package Geo::Coordinates::ITM;
2              
3 2     2   105886 use warnings;
  2         4  
  2         70  
4 2     2   12 use strict;
  2         2  
  2         79  
5              
6 2     2   10 use base qw( Exporter );
  2         8  
  2         275  
7              
8             our @EXPORT_OK = qw( ll_to_grid grid_to_ll );
9              
10 2     2   11 use Carp;
  2         4  
  2         164  
11 2     2   3722 use Math::Trig;
  2         91464  
  2         5452  
12              
13             =head1 NAME
14              
15             Geo::Coordinates::ITM - Convert coordinates between lat/lon and Irish Transverse Mercator
16              
17             =head1 VERSION
18              
19             This document describes Geo::Coordinates::ITM version 0.02
20              
21             =cut
22              
23             our $VERSION = '0.02';
24              
25             =head1 SYNOPSIS
26              
27             use Geo::Coordinates::ITM qw( ll_to_grid grid_to_ll );
28              
29             my ( $lat, $lon ) = grid_to_ll( $east, $north );
30             my ( $east, $north ) = ll_to_grid( $lat, $lon );
31            
32             =head1 DESCRIPTION
33              
34             Convert back and forth between Irish Transverse Mercator grid and WGS84.
35             The conversion code was stolen wholesale from L.
36              
37             http://svn.geograph.org.uk/svn/branches/british-isles/libs/geograph \
38             /conversionslatlong.class.php
39              
40             Nothing is exported by default. The exportable functions are
41             C and C.
42              
43             =head1 INTERFACE
44              
45             =head2 C<< ll_to_grid >>
46              
47             Convert a latitude, longitude (WGS84) coordinate pair into an ITM
48             easting and northing.
49              
50             my ( $east, $north ) = ll_to_grid( $lat, $lon );
51              
52             =cut
53              
54             sub ll_to_grid {
55 2     2 1 1115 my ( $lat, $long ) = @_;
56              
57             return (
58 2         8 _ll2e(
59             $lat, $long, 6378137, 6356752.314,
60             600000, 0.999820, 53.50000, -8.00000
61             ),
62             _ll2n(
63             $lat, $long, 6378137, 6356752.314,
64             600000, 750000, 0.999820, 53.50000,
65             -8.00000
66             )
67             );
68             }
69              
70             =head2 C<< grid_to_ll >>
71              
72             Convert an ITM easting, northing pair to a WGS84 latitude, longitude.
73              
74             my ( $lat, $lon ) = grid_to_ll( $east, $north );
75              
76             =cut
77              
78             sub grid_to_ll {
79 2     2 1 1120 my ( $e, $n ) = @_;
80              
81             return (
82 2         10 _en2lat(
83             $e, $n, 6378137, 6356752.314,
84             600000, 750000, 0.999820, 53.50000,
85             -8.00000
86             ),
87             _en2lon(
88             $e, $n, 6378137, 6356752.314,
89             600000, 750000, 0.999820, 53.50000,
90             -8.00000
91             )
92             );
93             }
94              
95             sub _ll2e {
96 2     2   5 my ( $PHI, $LAM, $a, $b, $e0, $f0, $PHI0, $LAM0 ) = @_;
97              
98 2         7 my $RadPHI = deg2rad( $PHI );
99 2         23 my $RadLAM = deg2rad( $LAM );
100 2         14 my $RadPHI0 = deg2rad( $PHI0 );
101 2         16 my $RadLAM0 = deg2rad( $LAM0 );
102              
103 2         14 my $af0 = $a * $f0;
104 2         4 my $bf0 = $b * $f0;
105 2         6 my $e2 = ( $af0**2 - $bf0**2 ) / $af0**2;
106 2         4 my $n = ( $af0 - $bf0 ) / ( $af0 + $bf0 );
107 2         14 my $nu = $af0 / ( sqrt( 1 - ( $e2 * sin( $RadPHI )**2 ) ) );
108 2         5 my $rho = ( $nu * ( 1 - $e2 ) ) / ( 1 - ( $e2 * sin( $RadPHI )**2 ) );
109 2         3 my $eta2 = ( $nu / $rho ) - 1;
110 2         4 my $p = $RadLAM - $RadLAM0;
111 2         2 my $IV = $nu * ( cos( $RadPHI ) );
112              
113 2         9 my $V
114             = ( $nu / 6 )
115             * ( cos( $RadPHI )**3 )
116             * ( ( $nu / $rho ) - ( tan( $RadPHI )**2 ) );
117              
118 2         27 my $VI
119             = ( $nu / 120 )
120             * ( cos( $RadPHI )**5 )
121             * ( 5
122             - ( 18 * ( tan( $RadPHI )**2 ) )
123             + ( tan( $RadPHI )**4 )
124             + ( 14 * $eta2 )
125             - ( 58 * ( tan( $RadPHI )**2 ) * $eta2 ) );
126              
127 2         65 return $e0 + ( $p * $IV ) + ( $p**3 * $V ) + ( $p**5 * $VI );
128             }
129              
130             sub _ll2n {
131 2     2   4 my ( $PHI, $LAM, $a, $b, $e0, $n0, $f0, $PHI0, $LAM0 ) = @_;
132              
133 2         5 my $RadPHI = deg2rad( $PHI );
134 2         20 my $RadLAM = deg2rad( $LAM );
135 2         13 my $RadPHI0 = deg2rad( $PHI0 );
136 2         13 my $RadLAM0 = deg2rad( $LAM0 );
137              
138 2         10 my $af0 = $a * $f0;
139 2         3 my $bf0 = $b * $f0;
140 2         5 my $e2 = ( $af0**2 - $bf0**2 ) / $af0**2;
141 2         3 my $n = ( $af0 - $bf0 ) / ( $af0 + $bf0 );
142 2         10 my $nu = $af0 / ( sqrt( 1 - ( $e2 * sin( $RadPHI )**2 ) ) );
143 2         6 my $rho = ( $nu * ( 1 - $e2 ) ) / ( 1 - ( $e2 * sin( $RadPHI )**2 ) );
144 2         3 my $eta2 = ( $nu / $rho ) - 1;
145 2         2 my $p = $RadLAM - $RadLAM0;
146 2         13 my $M = _marc( $bf0, $n, $RadPHI0, $RadPHI );
147 2         3 my $I = $M + $n0;
148 2         5 my $II = ( $nu / 2 ) * ( sin( $RadPHI ) ) * ( cos( $RadPHI ) );
149 2         6 my $III
150             = ( ( $nu / 24 ) * ( sin( $RadPHI ) ) * ( cos( $RadPHI )**3 ) )
151             * ( 5 - ( tan( $RadPHI )**2 ) + ( 9 * $eta2 ) );
152 2         26 my $IIIA
153             = ( ( $nu / 720 ) * ( sin( $RadPHI ) ) * ( cos( $RadPHI )**5 ) )
154             * ( 61 - ( 58 * ( tan( $RadPHI )**2 ) ) + ( tan( $RadPHI )**4 ) );
155              
156 2         41 return $I + ( $p**2 * $II ) + ( $p**4 * $III ) + ( $p**6 * $IIIA );
157             }
158              
159             sub _en2lat {
160 2     2   5 my ( $East, $North, $a, $b, $e0, $n0, $f0, $PHI0, $LAM0 ) = @_;
161              
162 2         8 my $RadPHI0 = deg2rad( $PHI0 );
163 2         36 my $RadLAM0 = deg2rad( $LAM0 );
164              
165 2         16 my $af0 = $a * $f0;
166 2         5 my $bf0 = $b * $f0;
167 2         17 my $e2 = ( $af0**2 - $bf0**2 ) / $af0**2;
168 2         5 my $n = ( $af0 - $bf0 ) / ( $af0 + $bf0 );
169 2         4 my $Et = $East - $e0;
170              
171 2         6 my $PHId = _init_lat( $North, $n0, $af0, $RadPHI0, $n, $bf0 );
172              
173 2         10 my $nu = $af0 / ( sqrt( 1 - ( $e2 * ( sin( $PHId )**2 ) ) ) );
174 2         4 my $rho = ( $nu * ( 1 - $e2 ) ) / ( 1 - ( $e2 * sin( $PHId )**2 ) );
175 2         5 my $eta2 = ( $nu / $rho ) - 1;
176              
177 2         7 my $VII = ( tan( $PHId ) ) / ( 2 * $rho * $nu );
178              
179 2         36 my $VIII
180             = ( ( tan( $PHId ) ) / ( 24 * $rho * $nu**3 ) )
181             * ( 5
182             + ( 3 * ( tan( $PHId )**2 ) )
183             + $eta2
184             - ( 9 * $eta2 * ( tan( $PHId )**2 ) ) );
185              
186 2         73 my $IX
187             = ( ( tan( $PHId ) ) / ( 720 * $rho * $nu**5 ) )
188             * ( 61
189             + ( 90 * ( ( tan( $PHId ) ) ^ 2 ) )
190             + ( 45 * ( tan( $PHId )**4 ) ) );
191              
192 2         73 return ( 180 / pi )
193             * ( $PHId
194             - ( $Et**2 * $VII )
195             + ( $Et**4 * $VIII )
196             - ( ( $Et**6 ) * $IX ) );
197             }
198              
199             sub _en2lon {
200 2     2   4 my ( $East, $North, $a, $b, $e0, $n0, $f0, $PHI0, $LAM0 ) = @_;
201              
202 2         5 my $RadPHI0 = deg2rad( $PHI0 );
203 2         20 my $RadLAM0 = deg2rad( $LAM0 );
204              
205 2         13 my $af0 = $a * $f0;
206 2         3 my $bf0 = $b * $f0;
207 2         5 my $e2 = ( $af0**2 - $bf0**2 ) / $af0**2;
208 2         4 my $n = ( $af0 - $bf0 ) / ( $af0 + $bf0 );
209 2         3 my $Et = $East - $e0;
210              
211 2         3 my $PHId = _init_lat( $North, $n0, $af0, $RadPHI0, $n, $bf0 );
212              
213 2         6 my $nu = $af0 / ( sqrt( 1 - ( $e2 * ( sin( $PHId )**2 ) ) ) );
214 2         4 my $rho = ( $nu * ( 1 - $e2 ) ) / ( 1 - ( $e2 * sin( $PHId )**2 ) );
215 2         25 my $eta2 = ( $nu / $rho ) - 1;
216              
217 2         5 my $X = ( cos( $PHId )**-1 ) / $nu;
218 2         10 my $XI = ( ( cos( $PHId )**-1 ) / ( 6 * $nu**3 ) )
219             * ( ( $nu / $rho ) + ( 2 * ( tan( $PHId )**2 ) ) );
220              
221 2         27 my $XII
222             = ( ( cos( $PHId )**-1 ) / ( 120 * $nu**5 ) )
223             * (
224             5 + ( 28 * ( tan( $PHId )**2 ) ) + ( 24 * ( tan( $PHId )**4 ) ) );
225              
226 2         42 my $XIIA
227             = ( ( cos( $PHId )**-1 ) / ( 5040 * $nu**7 ) )
228             * ( 61
229             + ( 662 * ( tan( $PHId )**2 ) )
230             + ( 1320 * ( tan( $PHId )**4 ) )
231             + ( 720 * ( tan( $PHId )**6 ) ) );
232              
233 2         74 return ( 180 / pi )
234             * ( $RadLAM0
235             + ( $Et * $X )
236             - ( $Et**3 * $XI )
237             + ( $Et**5 * $XII )
238             - ( $Et**7 * $XIIA ) );
239             }
240              
241             sub _init_lat {
242 4     4   8 my ( $North, $n0, $afo, $PHI0, $n, $bfo ) = @_;
243              
244 4         7 my $PHI1 = ( ( $North - $n0 ) / $afo ) + $PHI0;
245 4         9 my $M = _marc( $bfo, $n, $PHI0, $PHI1 );
246 4         8 my $PHI2 = ( ( $North - $n0 - $M ) / $afo ) + $PHI1;
247              
248 4         13 while ( abs( $North - $n0 - $M ) > 0.00001 ) {
249 8         9 $PHI2 = ( ( $North - $n0 - $M ) / $afo ) + $PHI1;
250 8         16 $M = _marc( $bfo, $n, $PHI0, $PHI2 );
251 8         22 $PHI1 = $PHI2;
252             }
253              
254 4         7 return $PHI2;
255             }
256              
257             sub _marc {
258 14     14   18 my ( $bf0, $n, $PHI0, $PHI ) = @_;
259 14         124 return $bf0 * (
260             (
261             ( 1 + $n + ( ( 5 / 4 ) * $n**2 ) + ( ( 5 / 4 ) * $n**3 ) )
262             * ( $PHI - $PHI0 )
263             ) - (
264             ( ( 3 * $n ) + ( 3 * $n**2 ) + ( ( 21 / 8 ) * $n**3 ) )
265             * ( sin( $PHI - $PHI0 ) )
266             * ( cos( $PHI + $PHI0 ) )
267             ) + (
268             ( ( ( 15 / 8 ) * $n**2 ) + ( ( 15 / 8 ) * $n**3 ) )
269             * ( sin( 2 * ( $PHI - $PHI0 ) ) )
270             * ( cos( 2 * ( $PHI + $PHI0 ) ) )
271             ) - (
272             ( ( 35 / 24 ) * $n**3 )
273             * ( sin( 3 * ( $PHI - $PHI0 ) ) )
274             * ( cos( 3 * ( $PHI + $PHI0 ) ) )
275             )
276             );
277             }
278              
279             1;
280             __END__