@ Ответ MikeLewis - гораздо более простой подход, но он дает вам только диапазон широты и долготы, и случайное рисование из этого может дать вам точки за пределами данного радиуса.
Следующее немного сложнее, но должно дать вам «лучшие» результаты. (Скорее всего, в этом нет необходимости, но я хотел попробовать :)).
Как и в случае ответа @MikeLewis, здесь предполагается, что Земля - это сфера. Мы используем это не только в формулах, но и при использовании вращательной симметрии.
Теория
Сначала мы выберем очевидный способ выбора случайного расстояния $distance
(меньше $radius
миль) и попытаемся найти случайную точку на расстоянии $distance
миль. Такие точки образуют круг на сфере, и вы можете быстро убедить себя, что простая параметризация этого круга трудна. Вместо этого мы рассмотрим особый случай: северный полюс.
Точки, которые находятся на заданном расстоянии от северного полюса, образуют круг на сфере фиксированной широты (90-($distance/(pi*3959)*180
). Это дает нам очень простой способ выбора случайной точки на этом круге: она будет иметь известную широту и случайную долготу.
Затем мы просто вращаем сферу, чтобы наш северный полюс находился в точке, которую нам изначально дали. Положение нашей случайной точки после этого вращения дает нам желаемую точку.
код
Примечание: Используемые здесь декартовы <-> сферические преобразования координат отличаются от обычных в литературе. Моя единственная мотивация для этого состояла в том, чтобы ось z (0,0,1)
указывала на север, а ось y (0,1,0)
указывала на вас и на точку с широтой и долготой, равной 0. Так что если вы хотите представить Землю Вы смотрите на Гвинейский залив.
/**
* Given a $centre (latitude, longitude) co-ordinates and a
* distance $radius (miles), returns a random point (latitude,longtitude)
* which is within $radius miles of $centre.
*
* @param array $centre Numeric array of floats. First element is
* latitude, second is longitude.
* @param float $radius The radius (in miles).
* @return array Numeric array of floats (lat/lng). First
* element is latitude, second is longitude.
*/
function generate_random_point( $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 ) );
}