Bing将地理数据解压缩算法端口映射到PHP 我试图将微软的解压缩算法移植到java(或者是C++或C语言),因为那是微软。这是一种从Bing Maps Geodata API结果中获取压缩形状数据并将其扩展到lat/lon坐标的算法。他们已经在他们的网站上发布了他们的算法
我的数据库中存储了一个坐标列表,我正在尝试检索定义多边形以处理形状的坐标数组。我的结果不同。有人能指出两者之间的差异吗 编辑:我认为我的问题在于PHP不处理长类型整数,并且在执行逐位运算时会发生精度损失。我可能需要转换一些操作以使用BCMath。帮帮忙 解压算法(微软的) 预期产出Bing将地理数据解压缩算法端口映射到PHP 我试图将微软的解压缩算法移植到java(或者是C++或C语言),因为那是微软。这是一种从Bing Maps Geodata API结果中获取压缩形状数据并将其扩展到lat/lon坐标的算法。他们已经在他们的网站上发布了他们的算法,java,php,bing-maps,compression,bing-api,Java,Php,Bing Maps,Compression,Bing Api,我的数据库中存储了一个坐标列表,我正在尝试检索定义多边形以处理形状的坐标数组。我的结果不同。有人能指出两者之间的差异吗 编辑:我认为我的问题在于PHP不处理长类型整数,并且在执行逐位运算时会发生精度损失。我可能需要转换一些操作以使用BCMath。帮帮忙 解压算法(微软的) 预期产出 an array of coordinates 35.894309002906084, -110.72522000409663 35.893930979073048, -110.72577999904752 35.8
an array of coordinates
35.894309002906084, -110.72522000409663
35.893930979073048, -110.72577999904752
35.893744984641671, -110.72606003843248
35.893366960808635, -110.72661500424147
array(4) {
[0]=>
array(2) {
[0]=>
float(1.0E-5)
[1]=>
float(1.0E-5)
}
[1]=>
array(2) {
[0]=>
float(1.027027027027E-5)
[1]=>
float(1.0181818181818E-5)
}
[2]=>
array(2) {
[0]=>
float(1.0825825825826E-5)
[1]=>
float(1.0552188552189E-5)
}
[3]=>
array(2) {
[0]=>
float(1.1103603603604E-5)
[1]=>
float(1.0734006734007E-5)
}
}
我的输出
an array of coordinates
35.894309002906084, -110.72522000409663
35.893930979073048, -110.72577999904752
35.893744984641671, -110.72606003843248
35.893366960808635, -110.72661500424147
array(4) {
[0]=>
array(2) {
[0]=>
float(1.0E-5)
[1]=>
float(1.0E-5)
}
[1]=>
array(2) {
[0]=>
float(1.027027027027E-5)
[1]=>
float(1.0181818181818E-5)
}
[2]=>
array(2) {
[0]=>
float(1.0825825825826E-5)
[1]=>
float(1.0552188552189E-5)
}
[3]=>
array(2) {
[0]=>
float(1.1103603603604E-5)
[1]=>
float(1.0734006734007E-5)
}
}
因此,我们可以看到PHP输出没有被正确计算,我有一种感觉,这与Java中转换为长整数和对整数运行逐位操作的差异有关。PHP应该处理整数,不管它们是长的、浮点数还是整数,但我觉得我忽略了一些东西
我打赌问题与这条线有关。有人能指出差异吗
n |= ((long)b & 31) << k; // mask off the top bit and append the rest to the accumulator
n |=((长)b&31)我怀疑你的问题在于你转换了以下C代码:
在PHP代码中,将其转换为:
$nx = pow(($nx >> 1), (-($nx & 1)) );
$ny = pow(($ny >> 1), (-($ny & 1)) );
在C中,^是一种按位异或运算,而不是幂运算。PHP对按位异或使用相同的符号,因此请尝试将代码更改为:
$nx = ($nx >> 1) ^ (-($nx & 1));
$ny = ($ny >> 1) ^ (-($ny & 1));
我怀疑您的问题在于您转换了以下C#代码:
在PHP代码中,将其转换为:
$nx = pow(($nx >> 1), (-($nx & 1)) );
$ny = pow(($ny >> 1), (-($ny & 1)) );
在C中,^是一种按位异或运算,而不是幂运算。PHP对按位异或使用相同的符号,因此请尝试将代码更改为:
$nx = ($nx >> 1) ^ (-($nx & 1));
$ny = ($ny >> 1) ^ (-($ny & 1));
我已将C#代码转换为PHP。问题确实在于php中的大浮点数会丢失精度。由于一些值超出了32位整数的边界,并且在C#中存储为64位整数,因此必须将这些值转换为。GMP支持长的按位操作
/*
* Microsoft's decompression algorithm - php version
* returns an array of coordinates (pairs of doubles)
*/
function tryParseEncodedValue($value) {
$safeCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
$list = array();
(int)$index = 0;
(int)$xsum = 0;
(int)$ysum = 0;
while ($index < strlen($value)) // While we have more data,
{
$n = 0; // initialize the accumulator
$k = 0; // initialize the count of bits
while (true)
{
if ($index >= strlen($value)) // If we ran out of data mid-number
{
var_error_log('failed: inxed >= strlen($value)');
return false; // indicate failure.
}
$b = strpos($safeCharacters, $value[$index++]);
if ($b === false) { // If the character wasn't on the valid list,
var_error_log('failed: character not in valid list');
return false; // indicate failure.
}
// mask off the top bit and append the rest to the accumulator
// n |= ((long)b & 31) << k;
$bgmp = gmp_init($b); // Here i'm breaking out this function
$bitwiseand = gmp_and($bgmp, 31); // on multiple lines because there's
$shifted = gmp_shiftl($bitwiseand, $k); // so many steps
$n = gmp_or($n, $shifted);
$k += 5;
if (gmp_cmp($bgmp, gmp_init(32)) < 0) break; // gmp compare: b < 32
}
// The resulting number encodes an x, y pair in the following way:
//
// ^ Y
// |
// 14
// 9 13
// 5 8 12
// 2 4 7 11
// 0 1 3 6 10 ---> X
// determine which diagonal it's on
//$diagonal = (int)((sqrt(8 * $n + 5) - 1) / 2);
$diagonal = gmp_intval(gmp_div_q(gmp_sub(gmp_sqrt(gmp_add(gmp_mul($n, 8), 5)), 1), 2));
// subtract the total number of points from lower diagonals
// n -= diagonal * (diagonal + 1L) / 2;
$n = gmp_sub($n, gmp_div_q(gmp_mul($diagonal, gmp_add($diagonal, 1)), 2));
// get the X and Y from what's left over
(int)$ny = gmp_intval($n);
(int)$nx = $diagonal - $ny;
// undo the sign encoding
$nx = ($nx >> 1)^ (-($nx & 1));
$ny = ($ny >> 1)^ (-($ny & 1));
// undo the delta encoding
$xsum += $nx;
$ysum += $ny;
// position the decimal point
$coordinate = array($ysum * 0.00001, $xsum * 0.00001);
array_push($list, $coordinate);
}
return $list;
}
// shift left, $x number to shift, $n shift n times.
function gmp_shiftl($x,$n) {
return(gmp_mul($x,gmp_pow(2,$n)));
}
/*
*微软的解压算法-php版本
*返回坐标数组(成对的双精度)
*/
函数tryParseEncodedValue($value){
$safeCharacters=“abcdefghijklmnopqrstuvxyzabdfghijklmnopqrstuvxyzo123456789_-”;
$list=array();
(int)$index=0;
(int)$xsum=0;
(int)$ysum=0;
while($index=strlen($value))//如果我们用完了中间数的数据
{
变量错误日志('failed:inx>=strlen($value');
返回false;//表示失败。
}
$b=strpos($safeCharacters,$value[$index++]);
如果($b==false){//如果字符不在有效列表中,
变量错误日志('失败:字符不在有效列表中');
返回false;//表示失败。
}
//屏蔽顶部位并将其余位附加到累加器
//n |=((长)b&31)X
//确定它在哪个对角线上
//$diagonal=(int)((sqrt(8*$n+5)-1)/2);
$diagonal=gmp_intval(gmp_div_q)(gmp_sub(gmp_sqrt)(gmp_add(gmp_mul($n,8),5)),1),2));
//从下对角线减去总点数
//n-=对角线*(对角线+1L)/2;
$n=gmp_sub($n,gmp_div_q(gmp_mul($diagonal,gmp_add($diagonal,1)),2));
//从剩下的东西中得到X和Y
(int)$ny=gmp_intval($n);
(int)$nx=$diagonal-$ny;
//撤消符号编码
$nx=($nx>>1)^($nx&1));
$ny=($ny>>1)^($ny&1));
//撤消增量编码
$xsum+=$nx;
$ysum+=$ny;
//定位小数点
$coordinate=array($ysum*0.00001,$xsum*0.00001);
数组推送($list,$coordinate);
}
返回$list;
}
//向左移位,$x要移位的次数,$n移位n次。
函数gmpu shiftl($x,$n){
返回(gmp_-mul($x,gmp_-pow(2,$n)));
}
我已将C#代码转换为PHP。问题确实在于PHP中的大浮点数丢失了精度。由于一些值超出了32位整数的边界,并在C#中存储为64位整数,因此必须将这些值转换为。GMP支持长位操作
/*
* Microsoft's decompression algorithm - php version
* returns an array of coordinates (pairs of doubles)
*/
function tryParseEncodedValue($value) {
$safeCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
$list = array();
(int)$index = 0;
(int)$xsum = 0;
(int)$ysum = 0;
while ($index < strlen($value)) // While we have more data,
{
$n = 0; // initialize the accumulator
$k = 0; // initialize the count of bits
while (true)
{
if ($index >= strlen($value)) // If we ran out of data mid-number
{
var_error_log('failed: inxed >= strlen($value)');
return false; // indicate failure.
}
$b = strpos($safeCharacters, $value[$index++]);
if ($b === false) { // If the character wasn't on the valid list,
var_error_log('failed: character not in valid list');
return false; // indicate failure.
}
// mask off the top bit and append the rest to the accumulator
// n |= ((long)b & 31) << k;
$bgmp = gmp_init($b); // Here i'm breaking out this function
$bitwiseand = gmp_and($bgmp, 31); // on multiple lines because there's
$shifted = gmp_shiftl($bitwiseand, $k); // so many steps
$n = gmp_or($n, $shifted);
$k += 5;
if (gmp_cmp($bgmp, gmp_init(32)) < 0) break; // gmp compare: b < 32
}
// The resulting number encodes an x, y pair in the following way:
//
// ^ Y
// |
// 14
// 9 13
// 5 8 12
// 2 4 7 11
// 0 1 3 6 10 ---> X
// determine which diagonal it's on
//$diagonal = (int)((sqrt(8 * $n + 5) - 1) / 2);
$diagonal = gmp_intval(gmp_div_q(gmp_sub(gmp_sqrt(gmp_add(gmp_mul($n, 8), 5)), 1), 2));
// subtract the total number of points from lower diagonals
// n -= diagonal * (diagonal + 1L) / 2;
$n = gmp_sub($n, gmp_div_q(gmp_mul($diagonal, gmp_add($diagonal, 1)), 2));
// get the X and Y from what's left over
(int)$ny = gmp_intval($n);
(int)$nx = $diagonal - $ny;
// undo the sign encoding
$nx = ($nx >> 1)^ (-($nx & 1));
$ny = ($ny >> 1)^ (-($ny & 1));
// undo the delta encoding
$xsum += $nx;
$ysum += $ny;
// position the decimal point
$coordinate = array($ysum * 0.00001, $xsum * 0.00001);
array_push($list, $coordinate);
}
return $list;
}
// shift left, $x number to shift, $n shift n times.
function gmp_shiftl($x,$n) {
return(gmp_mul($x,gmp_pow(2,$n)));
}
/*
*微软的解压算法-php版本
*返回坐标数组(成对的双精度)
*/
函数tryParseEncodedValue($value){
$safeCharacters=“abcdefghijklmnopqrstuvxyzabdfghijklmnopqrstuvxyzo123456789_-”;
$list=array();
(int)$index=0;
(int)$xsum=0;
(int)$ysum=0;
while($index=strlen($value))//如果我们用完了中间数的数据
{
变量错误日志('failed:inx>=strlen($value');
返回false;//表示失败。
}
$b=strpos($safeCharacters,$value[$index++]);
如果($b==false){//如果字符不在有效列表中,
变量错误日志('失败:字符不在有效列表中');
返回false;//表示失败。
}
//遮罩掉顶部的一位,然后消失