有问题的代码是第二个foreach循环中包含的代码,其目的是防止精确重复的纬度和经度。
foreach($aUsers as $k => $v)
{
// generate address
$aAddress = array();
if(!empty($v['city_location']))
$aAddress[] = $v['city_location'];
if(!empty($v['country_child_id']))
{
$aRow = $oDb->select('name')
->from(getT('country_child'))
->where('child_id = \''.$v['country_child_id'].'\'')
->execute('getRow');
$aAddress[] = $aRow['name'];
}
if(!empty($v['postal_code']))
$aAddress[] = $v['postal_code'];
if(!empty($v['country_iso']))
{
$aRow = $oDb->select('name')
->from(getT('country'))
->where('country_iso = \''.$v['country_iso'].'\'')
->execute('getRow');
$aAddress[] = $aRow['name'];
}
$sAddress = implode(', ',$aAddress);
/// get location
$aLatLon = $oGeoMap->getLatLon($v['user_id'],1,$sAddress);
if($aLatLon['success'] === true)
{
foreach($aUsers as $k2 => $v2)
{
$iAdd = .01;
$iAttempts = 0;
while($v2['latitude'] == $aLatLon['latitude'] && $v2['longitude'] == $aLatLon['longitude'])
{
$iAttempts++;
switch($iAttempts){
case 1:
$aLatLon['latitude'] += $iAdd;
break;
case 2:
$aLatLon['longitude'] += $iAdd;
break;
case 3:
$aLatLon['latitude'] += $iAdd;
$aLatLon['longitude'] += $iAdd;
break;
case 4:
$aLatLon['latitude'] -= $iAdd;
$aLatLon['longitude'] -= $iAdd;
break;
case 5:
$aLatLon['latitude'] += $iAdd;
$aLatLon['longitude'] -= $iAdd;
break;
case 6:
$aLatLon['latitude'] -= $iAdd;
$aLatLon['longitude'] += $iAdd;
break;
case 7:
$iAdd += .01;
$iAttempts = 0;
break;
}
}
}
$aUsers[$k]['latitude'] = $aLatLon['latitude'];
$aUsers[$k]['longitude'] = $aLatLon['longitude'];
$aUsers[$k]['address'] = $sAddress;
}
else
unset($aUsers[$k]);
}
答案 0 :(得分:3)
我非常赞同弗兰克法默的评论,但如果你坚持这种做事方式,可以尝试以下几点:
$lls = array();
static $offs = array( array(1,0), array(0,1), array(1,1),
array(-1,-1), array(1,-1), array(-1,1) );
foreach($aUsers as $k=>&$v) {
$lla=$la=somelat; $llo=$lo=somelong;
for($add=.01;isset($lls["{$lla}x$llo"]);$add+=.01) {
foreach($offs as $o) {
$lla=$la+$o[0]*$add; $llo=$lo+$o[1]*$add;
if(!isset($lls["{$lla}x$llo"])) break;
}
}
$lls["{$lla}x$llo"] = true;
$v['latitiude']=$lla; $v['longtitude']=$llo;
$v['address'] = $sAddress;
}
也就是说,如果我理解你的意图。并自行更改变量名称以符合您的标准; - )
代码未经测试。
不,我不会重新阅读完整的代码; - )
答案 1 :(得分:2)
您可以尝试使用包含现有纬度+经度位置的第二个数据结构,例如由纬度经度索引的二维用户数组。您可以检查该另一个数据结构中是否存在给定的纬度和经度,而不是遍历$aUsers
数组。
请注意,由于只能将整数和字符串用作数组键并将浮点数转换为整数或字符串会导致精度损失,因此如果您是浮点数,则应将浮点数转换为其位数字等效值使用纬度和经度作为键。一个简单的pack('d', $l)
应该可以使用,或者您可以使用:
function fl2hex($l, $fmt='d') {
$hex = unpack('H*', pack($fmt, $l));
return $hex[1];
}
如果您知道您的纬度和经度存储为浮点数而不是双精度数(虽然我相当确定PHP仅使用双精度数),您可以使用'f'作为包格式而不是'd'。
为了便于阅读,您可以将部分代码(例如switch($iAttempts)
)重构为附加功能。
对于单个位置的多人问题,另一种解决方案(假设地图显示在屏幕上而不是打印)是为一组人使用不同的指示器。当用户将鼠标悬停在组图标上时,它可以“爆炸”成一个单独图标的星形(如果这是有意义的),每个图标都有一条线将图标连接到人的位置。我在几个应用程序中看到了类似的东西,但现在无法想出哪些。
答案 2 :(得分:0)
你可以使用带分号的switch()......例如
switch($attempts) {
case 1;
case 3;
case 5;
$aLatLon['latitude'] += $iAdd;
break;
}
没有测试过这个;但我相信如果你继续像这样或类似的东西,它会工作。
希望有帮助
答案 3 :(得分:0)
这是对所有代码的一般性建议,而不仅仅是内部循环。我会更改代码以使用专用结构而不是数组。这是一个基本的例子:
foreach($aUsers as $k => $v)
{
$userInfo = new UserInfo($v);
// generate address
$sAddress = $userInfo->getAddress();
/// get location
$latLonResult = $oGeoMap->getLatLon($userInfo->user_id, 1, $sAddress);
...
}
就优化内循环而言,我只是删除该代码。要么想出一个新的UI元素,让多个用户在同一个位置,要么在用户已经将lat / long添加到地图时忽略用户。
如果你必须保留它,迈克尔的解决方案看起来很好。