在现有坐标的半径内生成随机地理坐标

Generate random geo coordinates within radius of existing coordinates

我想在给定坐标的给定半径内生成坐标。 我写了一个小脚本,大部分时间生成有效值:


const coordinate = [Math.random() * 180 - 90, Math.random() * 360 - 180]; // [lat, long]
const angleRadians = Math.PI / 4; // "random" angle in ° radians
const totalDistance = 100; // max distance in km

// First calculate the new latitude
const kmPerDegreeLatitude = 111; // in km/°
const distanceLatitude = totalDistance / kmPerDegreeLatitude; // in °

const offsetLatitude = Math.sin(angleRadians) * distanceLatitude;
const newLatitude = coordinate[0] + offsetLatitude;

// This looks wrong to me, but reduces the likelihood of errors
const remainingDistance = Math.sqrt(
  Math.pow(totalDistance, 2) -
    Math.pow(offsetLatitude * kmPerDegreeLatitude, 2)
);

// Now calculate the longitude
const kmPerDegreeLongitude =
  Math.abs(Math.cos(degreesToRadians(newLatitude))) * 111; // in km/°
const distanceLongitude = remainingDistance / kmPerDegreeLongitude; // in °

const offsetLongitude = Math.cos(angleRadians) * distanceLongitude;
const newLongitude = coordinate[1] + offsetLongitude;

// Done
const newCoordinate: [latitude: number, longitude: number] = [
  newLatitude,
  newLongitude,
];

但是当我使用以下代码检查距离时,我有时会超出允许的距离:

function haversine(
  latitude1: number,
  longitude1: number,
  latitude2: number,
  longitude2: number,
) {
  const EQUATORIAL_EARTH_RADIUS = 6378.137;
  const distanceLatitude = degreesToRadians(latitude2 - latitude1);
  const distanceLongitude = degreesToRadians(longitude2 - longitude1);
  const a =
    Math.sin(distanceLatitude / 2) * Math.sin(distanceLatitude / 2) +
    Math.cos(degreesToRadians(latitude1)) *
      Math.cos(degreesToRadians(latitude2)) *
      Math.sin(distanceLongitude / 2) *
      Math.sin(distanceLongitude / 2);
  const distance =
    EQUATORIAL_EARTH_RADIUS * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

  return distance;
}

知道吗,我哪里搞砸了?我假设它在坐标生成中,但它可能在验证步骤中。 或者是否有更简单的方法来生成附近的坐标?

请注意,我无法为此使用现有的库,因为生成的坐标应该是可重现的,但为了简单起见,我省略了相关代码。

好吧,我试图让事情变得过于复杂,由于堆栈调用,JS 中的浮点数不精确有时会堆积到 20%。

我现在简化了计算,假设我们生活在一个完美的球体上:

const angleRadians = randomAngle(); // in ° radians

const errorCorrection = 0.995; // avoid float issues
const distanceInKm = randomDinstance(100) * errorCorrection; // in km

const distanceInDegree = distanceInKm / kmPerDegree; // in °

const newCoordinate: [latitude: number, longitude: number] = [
  coordinate[0] + Math.sin(angleRadians) * distanceInDegree,
  coordinate[1] + Math.cos(angleRadians) * distanceInDegree,
];

// Box latitude [-90°, 90°]
newCoordinate[0] = newCoordinate[0] % 180;
if (newCoordinate[0] < -90 || newCoordinate[0] > 90) {
  newCoordinate[0] = Math.sign(newCoordinate[0]) * 180 - newCoordinate[0];
  newCoordinate[1] += 180;
}
// Box longitude [-180°, 180°]
newCoordinate[1] = (((newCoordinate[1] % 360) + 540) % 360) - 180;

假设你可以将地球表面局部近似为一个平面,那么下面的函数给你一个点P1的经纬度,给定一个点P0的经纬度,直线距离|P1 -P0| P1-P0与当地平行线的夹角。本地地球半径 R 也是必需的输入。

function incrementCoordinates (long0, lat0, dist, angle, R) {

    // Calculate the distance component along the parallel
    dist_x = dist * Math.cos(angle / 180 * Math.PI)

    // Calculate the distance component along the meridian
    dist_y = dist * Math.sin(angle / 180 * Math.PI)

    // Calculate the new longitude
    long1 = long0 + dist_x / R / Math.PI * 180

    // Calculate the new latitude
    lat1 = lat0 + dist_y / R / Math.PI * 180

    return [long1, lat1]
}