SAS 中的 Maidenhead Grid Square 函数,PHP 或 JavaScript

Maidenhead Grid Square Functions in SAS, PHP or JavaScript

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

%macro grid2latlong(网格);

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;

%修补;

你不是在计算质心,你是在计算正方形的左下边界,据我所知。要计算质心,看起来标准 Perl 例程维基百科参考会根据需要附加“..55LL55LL”(前两个显然必须存在,但之后 55 或 LL 将大致是网格块的中心点)。我假设 55LL 是 "standard",因为它在那里;您可以通过取左边界和右边界(下一个左边界)的平均值来更精确地计算它。

这是执行此操作的上述代码的略微简化版本。我把它写成一个数据步骤来简化测试,但当然把它变成一个宏是微不足道的。如果你有 FCMP(9.2+,最好是 9.4+)你当然可以把它写成一个实际的函数。

data have;
length grid ;
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;