生成位置周围的随机坐标

时间:2011-10-01 13:31:43

标签: php math

我想要一个接受地理位置(纬度,经度)并在其周围生成随机坐标集的函数,但也将这些参数作为计算的一部分:

  • 要制作的随机坐标数
  • 中生成的半径
  • 以米为单位的随机坐标之间的最小距离
  • 用于生成周围位置的根坐标。

生成方式的示例:

Example

实现这一目标的好方法是什么?

4 个答案:

答案 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-treebinary search tree(按x值和y值)。使用有序树,您将能够有效地获得 [x±min_distance,y±min_distance] 区域中的点。这些是唯一需要检查的点,大大减少了所需操作的数量。