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

SAS、PHP或JavaScript中的Maidenhead Grid Square函数,javascript,php,sas,latitude-longitude,Javascript,Php,Sas,Latitude Longitude,从概念上讲,我知道我需要做什么。但在数学上,我被难倒了。 我想最好在SAS中创建两个函数,但PHP或JavaScript也可以。第一个用于将纬度/经度转换为Maidenhead网格正方形,第二个用于查找给定网格正方形名称(即EM29qe78pq)的Maidenhead网格正方形中心的纬度和经度。我想两者都与所有10个字符的工作,但仍然是足够灵活,只需要他们6和8。 我读了又读了维基百科的文章,但总是提出错误的价值观。我已经在谷歌上搜索了100多次寻求帮助,但没有一次是这样。我意识到我只是不理解这

从概念上讲,我知道我需要做什么。但在数学上,我被难倒了。 我想最好在SAS中创建两个函数,但PHP或JavaScript也可以。第一个用于将纬度/经度转换为Maidenhead网格正方形,第二个用于查找给定网格正方形名称(即EM29qe78pq)的Maidenhead网格正方形中心的纬度和经度。我想两者都与所有10个字符的工作,但仍然是足够灵活,只需要他们6和8。 我读了又读了维基百科的文章,但总是提出错误的价值观。我已经在谷歌上搜索了100多次寻求帮助,但没有一次是这样。我意识到我只是不理解这个问题的数学部分。这是一个简单的数学,我听说了。 这是SAS宏,我已经将网格正方形转换为lat/lon,但在关闭时,它不正确。有人愿意帮我调查一下,也许能给我答案

%宏grid2latlong(网格)


%修补

根据我的理解,你不是在计算质心,而是在计算正方形的左下边界。为了计算质心,标准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;

对于一些样本数据、样本正确的结果和一些关于如何出错的信息(即样本错误的结果),这是一个更好的问题。对于宏调用,测试参数应为EM29qe78pq。结果应该是39.202953,-94.602885,或者距离该值不到一秒的某个值。我通常可以计算到39.2000,-94.6000,但不能更接近。那么一个10个字符的方格的中心大约是一个普通房子的中间。我经常使用的例子是EM29qe78pq,因为我知道确切的答案非常接近39.202953,-94.602885。你上面的算法给出的是39.202777778,-94.603125,比我得到的要近得多。而且足够接近它的目标。非常感谢你的帮助。
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;