多边形内随机分布点位(地图相关)

455 阅读1分钟

在开发的过程中,往往都有奇奇怪怪的需求,就比如地图上渲染多个多边形,蛋疼的是多边形内需要随机分布点位,用以展示该多边形的点位信息。

首先,我们需要计算多边形的最小边界框,也就是多边形的坐标组中最大的经度(longitude)、纬度(latitude)和最小的经度和纬度。

let minX = Infinity,
    maxX = -Infinity,
    minY = Infinity,
    maxY = -Infinity;
  for (let i = 0; i < polygonVertices.length; i++) {
    if (polygonVertices[i][0] < minX) {
      minX = polygonVertices[i][0];
    }
    if (polygonVertices[i][0] > maxX) {
      maxX = polygonVertices[i][0];
    }t
    if (polygonVertices[i][1] < minY) {
      minY = polygonVertices[i][1];
    }
    if (polygonVertices[i][1] > maxY) {
      maxY = polygonVertices[i][1];
    }
  }

其次,我们要计算出一个点位是否在多边形内。

function isPointInPolygon(point: number[], polygonVertices: number[][]): boolean {
  let inside = false;

  // 射线法判断点是否在多边形内部
  for (let i = 0, j = polygonVertices.length - 1; i < polygonVertices.length; j = i++) {
    const xi = polygonVertices[i][0], yi = polygonVertices[i][1];
    const xj = polygonVertices[j][0], yj = polygonVertices[j][1];
    const intersect = ((yi > point[1]) !== (yj > point[1])) && (point[0] < (xj - xi) * (point[1] - yi) / (yj - yi) + xi);
    if (intersect) {
      inside = !inside;
    }
  }
  return inside;
}

然后在这个多边形的边界框里随机生成 n 个点位,并判断每个随机生成的点位是否在这个多边形内,如果是就存储在 points 。

  const points: number[][] = [];  while (points.length < n) {
    const x = Math.random() * (maxX - minX) + minX;
    const y = Math.random() * (maxY - minY) + minY;
    const point: number[] = [x, y];
    if (isPointInPolygon(point, polygonVertices)) {
      points.push(point);
    }
  }

完整代码:

function randomPointsInPolygon(polygonVertices: number[][], numPoints: number): number[][] {
  let minX = Infinity,
    maxX = -Infinity,
    minY = Infinity,
    maxY = -Infinity;
  for (let i = 0; i < polygonVertices.length; i++) {
    if (polygonVertices[i][0] < minX) {
      minX = polygonVertices[i][0];
    }
    if (polygonVertices[i][0] > maxX) {
      maxX = polygonVertices[i][0];
    }
    if (polygonVertices[i][1] < minY) {
      minY = polygonVertices[i][1];
    }
    if (polygonVertices[i][1] > maxY) {
      maxY = polygonVertices[i][1];
    }
  }
  // 在最小边界框内随机生成点位,直到有numPoints个点位在多边形内部
  const points: number[][] = [];
  while (points.length < numPoints) {
    const x = Math.random() * (maxX - minX) + minX;
    const y = Math.random() * (maxY - minY) + minY;
    const point: number[] = [x, y];
    if (isPointInPolygon(point, polygonVertices)) {
      points.push(point);
    }
  }
  return points;
}

function isPointInPolygon(point: number[], polygonVertices: number[][]): boolean {
  let inside = false;

  // 射线法判断点是否在多边形内部
  for (let i = 0, j = polygonVertices.length - 1; i < polygonVertices.length; j = i++) {
    const xi = polygonVertices[i][0], yi = polygonVertices[i][1];
    const xj = polygonVertices[j][0], yj = polygonVertices[j][1];
    const intersect = ((yi > point[1]) !== (yj > point[1])) && (point[0] < (xj - xi) * (point[1] - yi) / (yj - yi) + xi);
    if (intersect) {
      inside = !inside;
    }
  }
  return inside;
}