In a simulation (not using any GIS), I need to generate a random location that is within a specified distance of a given location. I found a very helpful post here on this exact topic: How to generate random locations nearby my location?
I see the answer that whuber helpfully provided, but I have two questions on it. First, for ease of reading, here is whuber's answer:
- To generate points uniformly, randomly, and independently within a circle of radius r around a location (x0, y0), start by generating two independent uniform random values u and v in the interval [0, 1). (This is what almost every random number generator provides you.) Compute
:
w = r * sqrt(u)
t = 2 * Pi * v
x = w * cos(t)
y = w * sin(t)
The desired random point is at location (x+x0, y+y0).
When using geographic (lat,lon) coordinates, then x0 (longitude) and y0 (latitude) will be in degrees but r will most likely be in meters (or feet or miles or some other linear measurement). First, convert the radius r into degrees as if you were located near the equator. Here, there are about 111,300 meters in a degree.
Second, after generating x and y as in step (1), adjust the x-coordinate for the shrinking of the east-west distances:
x' = x / cos(y0)
The desired random point is at location (x'+x0, y+y0). This is an approximate procedure. For small radii (less than a few hundred kilometers) that do not extend over either pole of the earth, it will usually be so accurate you cannot detect any error even when generating tens of thousands of random points around each center (x0,y0).
My questions:
First: Can anyone explain what the code is doing?
Specifically:
w = r * sqrt(u)
t = 2 * Pi * v
x = w * cos(t)
y = w * sin(t)
Second: When I implemented this, I found it frequently generated locations that slightly exceeded the radius limit. Stepping through the code, everything seemed fine up until the step marked Adjust the x-coordinate for the shrinking of the east-west distances, which is x' = x / cos(y0). That step often caused the longitude offset to get too large, making the resulting longitude jump outside the radius limit. Commenting that out avoids the problem, but I'd really like to understand this better.
Here is the C code:
----------
/*
* Notes:
* Uses information and algorithm from Stackexchange post:
* https://gis.stackexchange.com/questions/25877/how-to-generate-random-locations nearby-my-location
*/
int generate_random_location ( float ctr_lat, float ctr_long,
float radius_meters, float *new_lat,
float *new_long )
{
float radius_degrees = 0; /* radius in degrees */
float rand1 = 0; /* a random value between 0 and 1 */
float rand2 = 0; /* a random value between 0 and 1 */
float w = 0; /* intermediate value used in formula */
float t = 0; /* intermediate value used in formula */
float temp_long_off = 0; /* intermediate longitude offset (before lat adj) */
float lat_off = 0; /* calculated random latitude offset */
float long_off = 0; /* calculated random longitude offset */
int rslt = 0; /* error indication, if any */
/* convert input radius from meters to degrees */
radius_degrees = radius_meters / (float) METERS_PER_DEGREE_AT_EQUATOR;
/* random() returns a value from 0 to (2**31)-1; divide result by (2**31)-1
(which is 0xffffffff) to produce a random value between 0 and 1 */
rand1 = random() / (float) 0xffffffff;
rand2 = random() / (float) 0xffffffff;
/* these few lines are Greek to me -- no idea */
w = radius_degrees * sqrt ( rand1 );
t = 2 * M_PI * rand2;
temp_long_off = w * cos ( t ); /* intermediate offset for longitude */
lat_off = w * sin ( t ); /* offset for latitude */
//
// This adjustment is causing the distance to exceed the radius limit
//
/* Adjust longitide offset for the shrinking of east-west distances as
latitude moves away from the equator */
long_off = temp_long_off / cos ( ctr_lat );
/* The random point is at location (lat_off + center latitude,
long_off + center longitude ) */
*new_lat = ctr_lat + lat_off;
*new_long = ctr_long + long_off;
return ( rslt );
}
----------
w = r * sqrt(u)
uses the random numberu
(0-1) and the radius in degrees to create a random distance within the radius. The SQRT biases the distance to be closer to the maximum. That might be a problem in my simulation. 2.t = 2 * Pi * v
uses the random numberv
(0-1) to create a random angle in radians 3. Sincet
is then in degrees, the correctionx' = x / cos(y0)
isn't needed. 3. Did I get that right?