代码之家  ›  专栏  ›  技术社区  ›  Keith D Kaiser

SAS、PHP或JavaScript中的Maidenhead网格方形函数

  •  0
  • Keith D Kaiser  · 技术社区  · 10 年前

    从概念上讲,我明白我需要做什么。但在数学上我被难住了。 我想最好在SAS中创建两个函数,但PHP或JavaScript也可以。第一个将纬度/经度转换为梅登黑德网格广场,第二个查找给定网格广场名称(即EM29qe78pq)的梅登黑特网格广场中心的纬度和经度。我希望两者都能处理所有10个字符,但仍然足够灵活,只需要6个和8个字符。 我已经阅读并重新阅读了维基百科的文章 https://en.wikipedia.org/wiki/Maidenhead_Locator_System 但总是得出错误的值。我已经在谷歌上搜索了100多次寻求帮助,但没有一次找到。我意识到我只是不理解这个问题的数学部分。这是一个简单的数学…我被告知。 这是我将栅格正方形转换为lat/lon的SAS宏,但在关闭时,它不正确。有人愿意帮我调查一下,也许能给我答案。

    %宏网格latlong(网格);

    field = 'ABCDEFGHIJKLMNOPQRSTUVWX';
    
    array sparts $ 1 var1-var10;
    do i = 1 to length(&grid);
        sparts{i} = substr(&grid,i,1);
        lon1 = (find(field,var1)-1) * 20 - 180;
        lat1 = (find(field,var2)-1) * 10 - 90;
    
        lon2 = var3 * 2;
        lat2 = var4 * 1;
    
        lon3 = (find(field,var5)-1) * 5/60;
        lat3 = (find(field,var6)-1) * 2.5/60;
    
        lon4 = var7 * 0.0083333; 
        lat4 = var8 * 0.0041666; 
    
        lon5 = var9;
        lat5 = var10;
    
        lonx = sum(lon1,lon2,lon3,lon4); 
        latx = sum(lat1,lat2,lat3,lat4); 
    end;
    
    drop i var1-var8 lon4 lat4 lon1-lon3 lat1-lat3;
    

    %修补;

    1 回复  |  直到 10 年前
        1
  •  2
  •   Joe    10 年前

    你不是在计算质心,而是在计算正方形的左下边界,正如我所理解的。为了计算质心,看起来标准Perl例程Wikipedia引用根据需要附加了“..55LL55LL”(前两个显然必须存在,但之后55或LL将大致是网格平铺的中心点)。我假设55LL是“标准”,因为它存在于那里;通过取左边界和右边界(下一个左边界)的平均值,可以更精确地计算它。

    这是上面代码的一个稍微简化的版本。我将其作为数据步骤来编写,以简化测试,但当然,将其作为宏是微不足道的。如果你有FCMP(9.2+,更好的9.4+),你当然可以把它写成一个实际的函数。

    data have;
    length grid $10;
    input grid $;
    datalines;
    AB12CD34
    AB12CD
    AB12CD34EF
    ;;;;
    run;
    
    %let grid=grid;
    
    
    data want;
    set have;
    *Initialize some variables;
    latmult=10;  *the amount to multiply latitude values by (starting out);
    lonmult=20;  *the amount to multiply longitude values by (starting out);
    lon=-180;  *the zero point for longitude in this system;
    lat=-90;   *the zero point for latitude in this system;
    
    *append 5's and L's to the string if it is incomplete;
    *If you leave this out, this still works, but returns the edge not the center;
    
    initial_String='LL55LL55LL';
    substr(initial_String,1,length(&grid.)) = trim(&grid.);
    
    do i = 1 to length(initial_String) by 2;
    
        if mod((i+1)/2,2)=1 then do;  *letters;
            if I>1 then do;  *i=1 it is initialized properly already;
                lonmult=lonmult/24;
                latmult=latmult/24;
            end;
            *rank converts "A" to 65 and up through "Z" is 90.;
            lon=sum(lon,lonmult*(rank(upcase(char(initial_String,i)))-65));
            lat=sum(lat,latmult*(rank(upcase(char(initial_String,i+1)))-65));
        end;
        else do;
            latmult=latmult/10;
            lonmult=lonmult/10;
            lon=sum(lon,lonmult*input(char(initial_String,i),1.));
            lat=sum(lat,latmult*input(char(initial_String,i+1),1.));
        end;
    end;
    
    
    run;