Концептуально я понимаю, что мне нужно делать. Но математически я в тупике.
Я хотел бы создать две функции, желательно в SAS, но PHP или JavaScript тоже будут работать. Первый преобразовывает широту / долготу в квадрат сетки Maidenhead, второй находит широту и долготу для центра квадрата сетки Maidenhead по названию квадрата сетки (то есть EM29qe78pq). Я хотел бы, чтобы оба работали со всеми 10 символами, но при этом были достаточно гибкими, чтобы иметь только 6 и 8 символов.
Я прочитал и перечитал статью в Википедии https://en.wikipedia.org/wiki/Maidenhead_Locator_System но всегда придумывать неправильные значения. Я гуглил буквально более 100 раз в поисках помощи, но ни один из них не нашел. Я пришел к выводу, что просто не понимаю математическую часть этой проблемы. И его простая математика .. Мне сказали.
Это макрос SAS, у меня есть преобразование квадрата сетки в широты / долготы, но пока оно близко, это не правильно. Кто-нибудь захочет исследовать это для меня и, возможно, даст мне ответ.
% macro grid2latlong (grid);
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 является «стандартом», учитывая его присутствие там; Вы можете вычислить это более точно, взяв среднее значение левой границы и правой границы (следующая левая граница).
Вот несколько упрощенная версия вашего кода выше, которая делает это. Я пишу это как шаг данных, чтобы упростить тестирование, но, конечно, сделать его макросом тривиально. Если у вас есть 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;
Других решений пока нет …