在开发的过程中,往往都有奇奇怪怪的需求,就比如地图上渲染多个多边形,蛋疼的是多边形内需要随机分布点位,用以展示该多边形的点位信息。
首先,我们需要计算多边形的最小边界框,也就是多边形的坐标组中最大的经度(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;
}