You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JavaScript在SVG多边形内均匀分布n个点(灯光布置)

多边形内部均匀分布灯光点的解决方案

你的现有代码通过外接矩形生成网格点再过滤出多边形内部点,存在两个核心问题:

  • 最终生成的点数往往和目标数量偏差较大
  • 不规则多边形(比如凹户型)的边角区域点分布稀疏,无法实现真正的均匀分布

下面提供可行的解决思路及落地代码:

方案选型

  • 泊松圆盘采样:生成的点之间保持最小距离,分布自然均匀,适配任意多边形边界,计算效率适中,完全匹配家居灯光布置需求
  • 重心Voronoi划分:精度更高但计算复杂度大,适合专业级高均匀度要求场景
  • 偏移网格补点:实现成本低,但均匀度不如泊松采样,适合简单场景

推荐实现:适配多边形的泊松圆盘采样

替换原有的distributePoints函数,实现能保证点数和均匀度的采样逻辑:

function distributePoints(polygon, numberOfPoints) {
    const bounds = getPolygonBounds(polygon);
    const area = polygonArea(polygon);
    // 计算最小间距,匹配目标点数的密度
    const minDistance = Math.sqrt(area / (numberOfPoints * 1.5));
    const points = [];
    const candidates = [];

    // 生成第一个合法的内部起始点
    let firstPoint;
    do {
        firstPoint = {
            x: bounds.minX + Math.random() * (bounds.maxX - bounds.minX),
            y: bounds.minY + Math.random() * (bounds.maxY - bounds.minY)
        };
    } while (!isPointInPolygon(firstPoint, polygon));
    points.push(firstPoint);
    candidates.push(firstPoint);

    // 泊松采样核心逻辑
    while (candidates.length > 0 && points.length < numberOfPoints) {
        const candidateIndex = Math.floor(Math.random() * candidates.length);
        const candidate = candidates[candidateIndex];
        let found = false;

        // 尝试生成30个候选点,筛选符合条件的
        for (let i = 0; i < 30; i++) {
            const angle = Math.random() * Math.PI * 2;
            const distance = minDistance + Math.random() * minDistance;
            const newPoint = {
                x: candidate.x + Math.cos(angle) * distance,
                y: candidate.y + Math.sin(angle) * distance
            };

            // 校验:在多边形内,且与所有已有点距离达标
            if (isPointInPolygon(newPoint, polygon) && 
                points.every(p => Math.hypot(newPoint.x - p.x, newPoint.y - p.y) >= minDistance)) {
                points.push(newPoint);
                candidates.push(newPoint);
                found = true;
                if (points.length >= numberOfPoints) break;
            }
        }

        // 若当前候选点无法生成新点,移除出队列
        if (!found) {
            candidates.splice(candidateIndex, 1);
        }
    }

    // 极端情况补点,确保达到目标数量
    while (points.length < numberOfPoints) {
        let newPoint;
        do {
            newPoint = {
                x: bounds.minX + Math.random() * (bounds.maxX - bounds.minX),
                y: bounds.minY + Math.random() * (bounds.maxY - bounds.minY)
            };
        } while (!isPointInPolygon(newPoint, polygon));
        points.push(newPoint);
    }

    return points;
}

// 保留你原有的所有辅助函数:getPolygonBounds、polygonArea、isPointInPolygon等
// 原有的generateRandomSimplePolygon、renderVisualization函数可直接复用

代码说明

  1. 基于多边形面积和目标点数计算最小间距,确保点的密度均匀
  2. 从多边形内部随机选取起始点作为采样种子
  3. 对每个候选点,在其周围环形区域生成新点,仅保留符合「在多边形内+与所有已有点保持最小距离」条件的点
  4. 最后补全少量随机点,保证最终点数匹配需求

这种方式生成的点分布均匀,不会出现边角稀疏问题,完全适配家居墙体的SVG多边形场景。

内容的提问来源于stack exchange,提问作者Maheer Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 12:51:09