我想要一个接受地理位置(纬度,经度)并在其周围生成随机坐标集的函数,但也将这些参数作为计算的一部分:
生成方式的示例:
实现这一目标的好方法是什么?
答案 0 :(得分:7)
蛮力方法应该足够好。
for each point to generate "n"
find a random angle
get the x and y from the angle * a random radius up to max radius
for each point already generated "p"
calculate the distance between "n" and "p"
if "n" satisfies the min distance
add new point "n"
在PHP中,生成新点很容易
$angle = deg2rad(mt_rand(0, 359));
$pointRadius = mt_rand(0, $radius);
$point = array(
'x' => sin($angle) * $pointRadius,
'y' => cos($angle) * $pointRadius
);
然后计算两点之间的距离
$distance = sqrt(pow($n['x'] - $p['x'], 2) + pow($n['y'] - $p['y'], 2));
** 修改 **
为了澄清其他人所说的内容,并在做了一些进一步的研究之后(我不是数学家,但是的评论让我想知道),这里最简单的定义是高斯分布:
如果你是1维,那么$ pointRadius = $ x * mt_rand(0, $半径);没关系,因为没有区别 当$ x具有高斯分布时$ radius和$ x。
但是,如果坐标($ x,$ y,...)具有,则在2维或更多维中 高斯分布然后半径$ radius没有 高斯分布。
实际上$ radius ^ 2在2维中的分布[或k 维度]是所谓的“卡方分布2 [或 k]自由度“,条件是($ x,$ y,...)是独立的 没有均值和等方差。
因此,要获得正态分布,您必须将生成的半径线更改为
$pointRadius = sqrt(mt_rand(0, $radius*$radius));
正如其他人所建议的那样。
答案 1 :(得分:4)
生成位置周围的随机坐标
print('hello world'); s = input()
用法
function generateRandomPoint($centre, $radius) {
$radius_earth = 3959; //miles
//Pick random distance within $distance;
$distance = lcg_value()*$radius;
//Convert degrees to radians.
$centre_rads = array_map( 'deg2rad', $centre );
//First suppose our point is the north pole.
//Find a random point $distance miles away
$lat_rads = (pi()/2) - $distance/$radius_earth;
$lng_rads = lcg_value()*2*pi();
//($lat_rads,$lng_rads) is a point on the circle which is
//$distance miles from the north pole. Convert to Cartesian
$x1 = cos( $lat_rads ) * sin( $lng_rads );
$y1 = cos( $lat_rads ) * cos( $lng_rads );
$z1 = sin( $lat_rads );
//Rotate that sphere so that the north pole is now at $centre.
//Rotate in x axis by $rot = (pi()/2) - $centre_rads[0];
$rot = (pi()/2) - $centre_rads[0];
$x2 = $x1;
$y2 = $y1 * cos( $rot ) + $z1 * sin( $rot );
$z2 = -$y1 * sin( $rot ) + $z1 * cos( $rot );
//Rotate in z axis by $rot = $centre_rads[1]
$rot = $centre_rads[1];
$x3 = $x2 * cos( $rot ) + $y2 * sin( $rot );
$y3 = -$x2 * sin( $rot ) + $y2 * cos( $rot );
$z3 = $z2;
//Finally convert this point to polar co-ords
$lng_rads = atan2( $x3, $y3 );
$lat_rads = asin( $z3 );
return array_map( 'rad2deg', array( $lat_rads, $lng_rads ) );
}
答案 2 :(得分:3)
正如另一个答案所说,最简单的方法是生成随机点,然后丢弃那些与其他点太接近的方法(如果有必要,也不要忘记检查到中心点的最小距离)。
然而,生成随机点比解释更难。首先,您需要随机选择半径。第二,你需要在大半径上有更多的分数(因为那里有“更多的空间”)。所以你不能只让半径成为一个统一的随机数。
而是选择0到$radius * $radius
之间的数字。然后取sqrt()
来找到要绘制的半径(这是有效的,因为面积与半径的平方成正比)。
我不知道php(在评论中看到Karolis的更正),但从另一个答案我认为这意味着:
$angle = deg2rad(mt_rand(0, 359));
$radius = sqrt(mt_rand(0, $max_radius * $max_radius));
然后按照前面描述的那样检查。
最后,不要忘记你可以达到一个你不能再生成点数的状态,所以你可能想在“try and discard”循环上设置一个上限,以避免在空格是一个无限循环时(接近)满。
ps作为评论在另一个答案上说,这是O(n ^ 2),因此不适合大量的积分。你可以在一定程度上解决这个问题,方法是通过半径对点进行排序,只考虑$min_distance
之差,只要$min_distance << $max_radius
(如图中所示);做得比这更好需要更复杂的解决方案(例如,在更大的半径也使用角度,或使用单独的四叉树来存储和比较位置)。但是对于几十个点,我想这不是必要的。
答案 3 :(得分:1)
其他人已经解释了你需要的数学。但我认为最有问题的部分是表现。当你只有50个点时,检查点之间距离的蛮力方法就足够了。但是当你有1000分甚至更多时,太慢了。对于1000点,这需要至少50万次操作。
因此,我的建议是将所有随机生成的点保存到B-tree或binary search tree(按x值和y值)。使用有序树,您将能够有效地获得 [x±min_distance,y±min_distance] 区域中的点。这些是唯一需要检查的点,大大减少了所需操作的数量。