【问题标题】:Random generating coordinates within a circle圆内随机生成坐标
【发布时间】:2015-03-26 10:39:28
【问题描述】:

场景
我正在尝试生成 500 到 1000 个随机坐标(纬度、经度),它们位于半径为 1 公里的圆内,中心点位于(5.418680、100.327829)。我正在尝试在 php 中对此进行编码,但未能这样做,因为我不知道应该为 $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))
);

我想到了另一种方法。我不想在圆内生成点,而是在正方形边界内生成点,然后应用Haversine大圆距离公式确定随机生成的点是否位于半径为1KM的圆内。

注意:生成的点可以相互重叠。

请告知,我需要大致了解我应该采取什么方法。提前致谢。

【问题讨论】:

  • Radius 应该与您的 latlong 相关并且在同一范围内。半径为 1 将是 latlong 空间中的 1 坐标。您必须计算出一公里有多少纬度,并将其用作您的半径。我在某处读到一拉特是 11 公里,但我敢肯定。使用它,1 公里将是 0.09 纬度。

标签: php google-maps math coordinates


【解决方案1】:

在圆的边界内创建随机点:

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

使用 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

【讨论】:

  • 现在我们都在你住的地方... :-)
  • 好的解决方案,像魔术一样工作。你介意解释一下这 4 行代码吗? var sw = bounds.getSouthWest(); var ne = bounds.getNorthEast(); var ptLat = Math.random() * (ne.lat() - sw.lat()) + sw.lat(); var ptLng = Math.random() * (ne.lng() - sw.lng()) + sw.lng();
  • @geocodezip API 如何检测圆的西南边界?是通过添加一个与圆相同半径的正方形作为边界吗?
  • google.maps.Circle object 有一个 getBounds 方法(发布的代码使用该方法)
【解决方案2】:

我会这样做:

  1. 选择两个独立的xy坐标,均匀地从区间[0,1]开始。
  2. 如果 x² + y² > 1,则您的点位于圆外。丢弃该样本并重试。不将正方形转换为圆形可确保均匀分布。
  3. 将圆中的坐标转换为球体上的纬度/经度。如果你想保持均衡分布,你可以在这里使用area-preserving map projection。但是由于半径远小于地球的半径,所以这并不重要,因此您可以使用一些更简单的投影来代替,除非您必须为均匀分布提供强有力的保证。

我想可能有一些方法可以避免第 2 步中的丢弃,但这可能会使事情变得更加复杂,所以对于实际应用,我会坚持这样做。

【讨论】:

  • 这种方法在两极和反子午线附近完全失效。
  • @RandytheDev:OP 写了一个半径约 1 公里的总区域。一个简单的azimuthal projection 将适用于地球上的任何此类区域。保留区域的地图也适用于更大的区域,包括极点和反子午线,只是数值精度可能是个问题。或者您是否有更多关于这应该以何种方式分解的详细信息?
猜你喜欢
  • 1970-01-01
  • 2023-01-07
  • 1970-01-01
  • 2021-10-03
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多