Changeset 18460


Ignore:
Timestamp:
08/22/14 08:52:44 (11 years ago)
Author:
Mathieu Morlighem
Message:

CHG: new utm to lat long routines

Location:
issm/trunk-jpl/src/m/coordsystems
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/src/m/coordsystems/utm2ll.m

    r6341 r18460  
    1 function  [Lat,Lon] = utm2ll(xx,yy,utmzone)
    2 % -------------------------------------------------------------------------
    3 % [Lat,Lon] = utm2ll(x,y,utmzone)
     1function [lat,lon]=utm2ll(x,y,f,datum,varargin)
     2%UTM2LL UTM to Lat/Lon coordinates precise conversion.
     3%   [LAT,LON]=UTM2LL(X,Y,ZONE) converts UTM coordinates X,Y (in meters)
     4%       defined in the UTM ZONE (integer) to latitude LAT and longitude LON
     5%       (in degrees). Default datum is WGS84.
    46%
    5 % Description: Function to convert vectors of UTM coordinates into Lat/Lon vectors (WGS84).
    6 % Some code has been extracted from UTMIP.m function by Gabriel Ruiz Martinez.
     7%       X and Y can be scalars, vectors or matrix. Outputs LAT and LON will
     8%       have the same size as inputs.
    79%
    8 % Inputs:on)
    9 %    -3.485713    7.801235 -119.955246  -17.759537  -94.799019  121.640266
     10%       For southern hemisphere points, use negative zone -ZONE.
    1011%
    11 % Example 2: If you need Lat/Lon coordinates in Degrees, Minutes and Seconds
    12 % [Lat, Lon]=utm2ll(x,y,utmzone);
    13 % LatDMS=dms2mat(deg2dms(Lat))
    14 %LatDMS =
    15 %    40.00         18.00         55.55
    16 %    46.00         17.00          2.01
    17 %    37.00         34.00         40.17
    18 %    28.00         38.00         44.33
    19 %    38.00         51.00         19.96
    20 %    25.00          3.00         42.41
    21 % LonDMS=dms2mat(deg2dms(Lon))
    22 %LonDMS =
    23 %    -3.00         29.00          8.61
    24 %     7.00         48.00          4.40
    25 %  -119.00         57.00         18.93
    26 %   -17.00         45.00         34.33
    27 %   -94.00         47.00         56.47
    28 %   121.00         38.00         24.96
     12%       UTM2LL(X,Y,ZONE,DATUM) uses specific DATUM for conversion. DATUM can be
     13%       a string in the following list:
     14%               'wgs84': World Geodetic System 1984 (default)
     15%               'nad27': North American Datum 1927
     16%               'clk66': Clarke 1866
     17%               'nad83': North American Datum 1983
     18%               'grs80': Geodetic Reference System 1980
     19%               'int24': International 1924 / Hayford 1909
     20%       or DATUM can be a 2-element vector [A,F] where A is semimajor axis (in
     21%       meters) and F is flattening of the user-defined ellipsoid.
    2922%
    30 % Author:
    31 %   Rafael Palacios
    32 %   Universidad Pontificia Comillas
    33 %   Madrid, Spain
    34 % Version: Apr/06, Jun/06, Aug/06
    35 % Aug/06: corrected m-Lint warnings
    36 %-------------------------------------------------------------------------
     23%       Notice:
     24%               - UTM2LL does not perform cross-datum conversion.
     25%               - precision is near a millimeter.
     26%
     27%
     28%       Reference:
     29%               I.G.N., Projection cartographique Mercator Transverse: Algorithmes,
     30%                  Notes Techniques NT/G 76, janvier 1995.
     31%
     32%   Author: Francois Beauducel, <beauducel@ipgp.fr>
     33%   Created: 2001-08-23
     34%   Updated: 2014-04-20
    3735
    38 % Argument checking
     36%       Copyright (c) 2001-2014, François Beauducel, covered by BSD License.
     37%       All rights reserved.
    3938%
    40 error(nargchk(3, 3, nargin)); %3 arguments required
    41 n1=length(xx);
    42 n2=length(yy);
    43 n3=size(utmzone,1);
    44 if (n1~=n2 || n1~=n3)
    45         error('x,y and utmzone vectors should have the same number or rows');
    46 end
    47 c=size(utmzone,2);
    48 if (c~=4)
    49         error('utmzone should be a vector of strings like "30 T"');
     39%       Redistribution and use in source and binary forms, with or without
     40%       modification, are permitted provided that the following conditions are
     41%       met:
     42%
     43%          * Redistributions of source code must retain the above copyright
     44%            notice, this list of conditions and the following disclaimer.
     45%          * Redistributions in binary form must reproduce the above copyright
     46%            notice, this list of conditions and the following disclaimer in
     47%            the documentation and/or other materials provided with the distribution
     48%                                 
     49%       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     50%       AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     51%       IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     52%       ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     53%       LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     54%       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     55%       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     56%       INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     57%       CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     58%       ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     59%       POSSIBILITY OF SUCH DAMAGE.
     60
     61% Available datums
     62datums = [ ...
     63        { 'wgs84', 6378137.0, 298.257223563 };
     64        { 'nad83', 6378137.0, 298.257222101 };
     65        { 'grs80', 6378137.0, 298.257222101 };
     66        { 'nad27', 6378206.4, 294.978698214 };
     67        { 'int24', 6378388.0, 297.000000000 };
     68        { 'clk66', 6378206.4, 294.978698214 };
     69];
     70
     71if nargin < 3
     72        error('Not enough input arguments.')
    5073end
    5174
    52 % Memory pre-allocation
    53 %
    54 Lat=zeros(n1,1);
    55 Lon=zeros(n1,1);
     75if all([numel(x),numel(y)] > 1) && any(size(x) ~= size(y))
     76        error('X and Y must be the same size or scalars.')
     77end
    5678
    57 % Main Loop
    58 %
    59 for i=1:n1
    60         if (utmzone(i,4)>'X' || utmzone(i,4)<'C')
    61                 fprintf('utm2ll: Warning utmzone should be a vector of strings like "30 T", not "30 t"\n');
     79if ~isnumeric(f) || ~isscalar(f) || f ~= round(f)
     80        error('ZONE must be a scalar integer.')
     81end
     82
     83if nargin < 4
     84        datum = 'wgs84';
     85end
     86
     87if ischar(datum)
     88        if ~any(strcmpi(datum,datums(:,1)))
     89                error('Unkown DATUM name "%s"',datum);
    6290        end
    63         if (utmzone(i,4)>'M')
    64                 hemis='N';   % Northern hemisphere
    65         else
    66                 hemis='S';
     91        k = find(strcmpi(datum,datums(:,1)));
     92        A1 = datums{k,2};
     93        F1 = datums{k,3};       
     94else
     95        if numel(datum) ~= 2
     96                error('User defined DATUM must be a vector [A,F].');
    6797        end
     98        A1 = datum(1);
     99        F1 = datum(2);
     100end
    68101
    69         x=xx(i);
    70         y=yy(i);
    71         zone=str2double(utmzone(i,1:2));
     102% constants
     103D0 = 180/pi;    % conversion rad to deg
     104maxiter = 100;  % maximum iteration for latitude computation
     105eps = 1e-11;    % minimum residue for latitude computation
    72106
    73         sa = 6378137.000000 ; sb = 6356752.314245;
     107K0 = 0.9996;                                                            % UTM scale factor
     108X0 = 500000;                                                            % UTM false East (m)
     109Y0 = 1e7*(f < 0);                                                       % UTM false North (m)
     110P0 = 0;                                                                         % UTM origin latitude (rad)
     111L0 = (6*abs(f) - 183)/D0;                                       % UTM origin longitude (rad)
     112E1 = sqrt((A1^2 - (A1*(1 - 1/F1))^2)/A1^2);     % ellpsoid excentricity
     113N = K0*A1;
    74114
    75         %   e = ( ( ( sa ^ 2 ) - ( sb ^ 2 ) ) ^ 0.5 ) / sa;
    76         e2 = ( ( ( sa ^ 2 ) - ( sb ^ 2 ) ) ^ 0.5 ) / sb;
    77         e2cuadrada = e2 ^ 2;
    78         c = ( sa ^ 2 ) / sb;
    79         %   alpha = ( sa - sb ) / sa;             %f
    80         %   ablandamiento = 1 / alpha;   % 1/f
     115% computing parameters for Mercator Transverse projection
     116C = coef(E1,0);
     117YS = Y0 - N*(C(1)*P0 + C(2)*sin(2*P0) + C(3)*sin(4*P0) + C(4)*sin(6*P0) + C(5)*sin(8*P0));
    81118
    82         X = x - 500000;
     119C = coef(E1,1);
     120zt = complex((y - YS)/N/C(1),(x - X0)/N/C(1));
     121z = zt - C(2)*sin(2*zt) - C(3)*sin(4*zt) - C(4)*sin(6*zt) - C(5)*sin(8*zt);
     122L = real(z);
     123LS = imag(z);
    83124
    84         if hemis == 'S' || hemis == 's'
    85                 Y = y - 10000000;
    86         else
    87                 Y = y;
    88         end
     125l = L0 + atan(sinh(LS)./cos(L));
     126p = asin(sin(L)./cosh(LS));
    89127
    90         S = ( ( zone * 6 ) - 183 );
    91         lat =  Y / ( 6366197.724 * 0.9996 );
    92         v = ( c / ( ( 1 + ( e2cuadrada * ( cos(lat) ) ^ 2 ) ) ) ^ 0.5 ) * 0.9996;
    93         a = X / v;
    94         a1 = sin( 2 * lat );
    95         a2 = a1 * ( cos(lat) ) ^ 2;
    96         j2 = lat + ( a1 / 2 );
    97         j4 = ( ( 3 * j2 ) + a2 ) / 4;
    98         j6 = ( ( 5 * j4 ) + ( a2 * ( cos(lat) ) ^ 2) ) / 3;
    99         alfa = ( 3 / 4 ) * e2cuadrada;
    100         beta = ( 5 / 3 ) * alfa ^ 2;
    101         gama = ( 35 / 27 ) * alfa ^ 3;
    102         Bm = 0.9996 * c * ( lat - alfa * j2 + beta * j4 - gama * j6 );
    103         b = ( Y - Bm ) / v;
    104         Epsi = ( ( e2cuadrada * a^ 2 ) / 2 ) * ( cos(lat) )^ 2;
    105         Eps = a * ( 1 - ( Epsi / 3 ) );
    106         nab = ( b * ( 1 - Epsi ) ) + lat;
    107         senoheps = ( exp(Eps) - exp(-Eps) ) / 2;
    108         Delt = atan(senoheps / (cos(nab) ) );
    109         TaO = atan(cos(Delt) * tan(nab));
    110         longitude = (Delt *(180 / pi ) ) + S;
    111         latitude = ( lat + ( 1 + e2cuadrada* (cos(lat)^ 2) - ( 3 / 2 ) * e2cuadrada * sin(lat) * cos(lat) * ( TaO - lat ) ) * ( TaO - lat ) ) * ...
    112                 (180 / pi);
     128L = log(tan(pi/4 + p/2));
    113129
    114         Lat(i)=latitude;
    115         Lon(i)=longitude;
     130% calculates latitude from the isometric latitude
     131p = 2*atan(exp(L)) - pi/2;
     132p0 = NaN;
     133n = 0;
     134while any(isnan(p0) | abs(p - p0) > eps) & n < maxiter
     135        p0 = p;
     136        es = E1*sin(p0);
     137        p = 2*atan(((1 + es)./(1 - es)).^(E1/2).*exp(L)) - pi/2;
     138        n = n + 1;
     139end
    116140
     141if nargout < 2
     142        lat = D0*[p(:),l(:)];
     143else
     144        lat = p*D0;
     145        lon = l*D0;
    117146end
     147
     148
     149%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     150function c = coef(e,m)
     151%COEF Projection coefficients
     152%       COEF(E,M) returns a vector of 5 coefficients from:
     153%               E = first ellipsoid excentricity
     154%               M = 0 for transverse mercator
     155%               M = 1 for transverse mercator reverse coefficients
     156%               M = 2 for merdian arc
     157
     158
     159if nargin < 2
     160        m = 0;
     161end
     162
     163switch m
     164        case 0
     165        c0 = [-175/16384, 0,   -5/256, 0,  -3/64, 0, -1/4, 0, 1;
     166           -105/4096, 0, -45/1024, 0,  -3/32, 0, -3/8, 0, 0;
     167           525/16384, 0,  45/1024, 0, 15/256, 0,    0, 0, 0;
     168          -175/12288, 0, -35/3072, 0,      0, 0,    0, 0, 0;
     169          315/131072, 0,        0, 0,      0, 0,    0, 0, 0];
     170         
     171        case 1
     172        c0 = [-175/16384, 0,   -5/256, 0,  -3/64, 0, -1/4, 0, 1;
     173             1/61440, 0,   7/2048, 0,   1/48, 0,  1/8, 0, 0;
     174          559/368640, 0,   3/1280, 0,  1/768, 0,    0, 0, 0;
     175          283/430080, 0, 17/30720, 0,      0, 0,    0, 0, 0;
     176       4397/41287680, 0,        0, 0,      0, 0,    0, 0, 0];
     177
     178        case 2
     179        c0 = [-175/16384, 0,   -5/256, 0,  -3/64, 0, -1/4, 0, 1;
     180         -901/184320, 0,  -9/1024, 0,  -1/96, 0,  1/8, 0, 0;
     181         -311/737280, 0,  17/5120, 0, 13/768, 0,    0, 0, 0;
     182          899/430080, 0, 61/15360, 0,      0, 0,    0, 0, 0;
     183      49561/41287680, 0,        0, 0,      0, 0,    0, 0, 0];
     184   
     185end
     186c = zeros(size(c0,1),1);
     187
     188for i = 1:size(c0,1)
     189    c(i) = polyval(c0(i,:),e);
     190end
Note: See TracChangeset for help on using the changeset viewer.