kopikaokao
kopikaokao

Reputation: 508

Random generating coordinates within a circle

Scenario
I am trying to generate 500 to 1000 random coordinates (lat,long) that lies within a circle with 1 kilometer radius where center point located at (5.418680, 100.327829). I am trying to code this in php but failed to do so as i have no idea what value should i provide for $radius.

$radius = ?;
$origin_x = 5.420525;
$origin_y = 100.319500;

$angle = deg2rad(mt_rand(0, 359));
$pointRadius = mt_rand(0, $radius);

$point[] = array(
    'x' => $origin_x + ($pointRadius * cos($angle)),
    'y' => $origin_y + ($pointRadius * sin($angle))
);

There is another approach came across my mind. Instead of generating point within a circle, i would like to generate point inside a boundary of square and then apply Haversine great circle distance formula to determine is the random generated point lies within the circle with 1KM radius.

Note: The generated point is fine to overlap each other.

Please advise, I need general idea of what approach should I take. Thanks in advance.

Upvotes: 2

Views: 4208

Answers (2)

geocodezip
geocodezip

Reputation: 161334

Create random points inside the bounds of the circle:

var bounds = circle.getBounds();
map.fitBounds(bounds);
var sw = bounds.getSouthWest();
var ne = bounds.getNorthEast();    
for (var i = 0; i < 100; i++) {
   // create a random point inside the bounds
   var ptLat = Math.random() * (ne.lat() - sw.lat()) + sw.lat();
   var ptLng = Math.random() * (ne.lng() - sw.lng()) + sw.lng();
   var point = new google.maps.LatLng(ptLat,ptLng);

If they are within the circle itself keep them (add them to the map in this case), otherwise discard them:

   if (google.maps.geometry.spherical.computeDistanceBetween(point,circle.getCenter()) < circle.getRadius()) {
     createMarker(map, point,"marker "+i);
     // break;  if only need one point
   } // else nothing.

Example using the Google Maps Javascript API v3:

var circle;
var infowindow = new google.maps.InfoWindow({});

function initialize() {
  var map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: new google.maps.LatLng(22.7964, 79.8456),
    mapTypeId: google.maps.MapTypeId.HYBRID
  });

  circle = new google.maps.Circle({
    center: map.getCenter(),
    radius: 1000, // meters
    strokeColor: "#0000FF",
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: "#0000FF",
    fillOpacity: 0.26
  });

  circle.setMap(map);

  var bounds = circle.getBounds();
  map.fitBounds(bounds);
  var sw = bounds.getSouthWest();
  var ne = bounds.getNorthEast();
  for (var i = 0; i < 100; i++) {
    var ptLat = Math.random() * (ne.lat() - sw.lat()) + sw.lat();
    var ptLng = Math.random() * (ne.lng() - sw.lng()) + sw.lng();
    var point = new google.maps.LatLng(ptLat, ptLng);
    if (google.maps.geometry.spherical.computeDistanceBetween(point, circle.getCenter()) < circle.getRadius()) {
      createMarker(map, point, "marker " + i);
      // break;
    }
  }

}

function createMarker(map, point, content) {
  var marker = new google.maps.Marker({
    position: point,
    map: map
  });
  google.maps.event.addListener(marker, "click", function(evt) {
    infowindow.setContent(content + "<br>" + marker.getPosition().toUrlValue(6));
    infowindow.open(map, marker);
  });
  return marker;
}
google.maps.event.addDomListener(window, 'load', initialize);
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="map" style="width: 530px; height: 500px">
</div>

fiddle

Upvotes: 1

MvG
MvG

Reputation: 60858

I'd do it like this:

  1. Choose two independent x and y coordinate, uniformly from the interval [0,1].
  2. If x² + y² > 1 your point lies outside the circle. Discard that sample and try again. Not transforming the square to the circle ensures equidistribution.
  3. Turn coordinates in the circle to lat/lon on the sphere. If you want to preserve equidistribution, you'd use an area-preserving map projection here. But as the radius is way smaller than the radius of the earth, this doesn't matter much, so you might use some simpler projection instead unless you have to provide strong guarantees for equidistribution.

I guess there might be ways to avoid the discarding in step 2, but that would probably make things way more complicated, so for practical applications I'd stick with this.

Upvotes: 1

Related Questions