首页 小组 问答 话题 好文 素材 用户 唠叨 我的社区

[分享]如何在 SVG 多边形内均匀分布点?

不爱phpLv.1普通用户
2024-08-25 10:33:10
0
17
SVG

如何在 JavaScript 中均匀分布点到 SVG 多边形内

在网页设计和数据可视化中,我们经常需要将点均匀分布在特定形状内,例如 SVG 多边形。直接根据多边形的边界矩形来分布点,会导致部分点落在多边形外部,无法满足需求。本文将探讨如何使用 JavaScript 在 SVG 多边形内均匀分布任意数量的点,并提供详细的代码示例和解释,帮助你轻松实现这一功能。

三角剖分与面积加权:精准分布的秘密

为了确保所有点都位于多边形的内部,并且尽可能均匀地分布,我们需要采取更精细的策略:

  1. 三角剖分 :将多边形分割成多个三角形。

  2. 面积加权 :根据每个三角形的面积计算权重,面积越大的三角形分配到的点数越多。

  3. 随机采样 :在每个三角形内部随机生成点,确保点均匀分布在三角形内。

JavaScript 代码实现:将理论付诸实践

以下是使用 JavaScript 在 SVG 多边形内均匀分布点的代码示例:

function distributePointsInPolygon(polygon, numberOfPoints) {
  // 使用三角剖分算法将多边形分割成三角形数组
  const triangles = triangulate(polygon); 
  // 计算所有三角形的总面积
  const totalArea = triangles.reduce((sum, triangle) => sum + triangleArea(triangle), 0);
  // 计算每个单位面积应该分配的点数
  const pointsPerArea = numberOfPoints / totalArea;
  // 用于存储最终生成的点
  const distributedPoints = [];

  // 遍历每个三角形
  triangles.forEach(triangle => {
    // 根据三角形面积计算应该分配的点数
    const trianglePoints = Math.floor(triangleArea(triangle) * pointsPerArea);
    // 在当前三角形内生成对应数量的随机点
    for (let i = 0; i < trianglePoints; i++) {
      distributedPoints.push(generateRandomPointInTriangle(triangle));
    }
  });

  // 返回所有生成的点
  return distributedPoints;
}

// 计算三角形面积
function triangleArea(triangle) {
  const [p1, p2, p3] = triangle;
  return Math.abs((p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)) / 2);
}

// 在三角形内生成随机点
function generateRandomPointInTriangle(triangle) {
  const [p1, p2, p3] = triangle;
  const r1 = Math.random();
  const r2 = Math.random();
  const s = Math.sqrt(r1);
  const x = p1.x + (p2.x - p1.x) * s * r2 + (p3.x - p1.x) * s * (1 - r2);
  const y = p1.y + (p2.y - p1.y) * s * r2 + (p3.y - p1.y) * s * (1 - r2);
  return { x, y };
}

// 三角剖分算法(示例,可以使用其他库或算法)
function triangulate(polygon) {
  // 此处需要实现具体的三角剖分算法,例如 earcut 算法
  // 返回一个包含多个三角形坐标的数组
}

代码解读:逐行分析,清晰易懂

  1. distributePointsInPolygon(polygon, numberOfPoints) 函数 :

    • 接受一个多边形对象 polygon 和要分布的点数 numberOfPoints 作为参数。

    • 调用 triangulate 函数将多边形分割成多个三角形,存储在 triangles 数组中。

    • 计算所有三角形的总面积 totalArea

    • 计算每个单位面积应该分配的点数 pointsPerArea

    • 创建 distributedPoints 数组用于存储最终生成的点。

    • 遍历每个三角形,根据其面积计算应该分配的点数 trianglePoints

    • 调用 generateRandomPointInTriangle 函数在当前三角形内生成对应数量的随机点,并将生成的点添加到 distributedPoints 数组中。

    • 最后返回 distributedPoints 数组,其中包含了所有生成的点。

  2. triangleArea(triangle) 函数 :

    • 接受一个三角形对象 triangle 作为参数。

    • 使用三角形顶点坐标计算三角形面积,并返回计算结果。

  3. generateRandomPointInTriangle(triangle) 函数 :

    • 接受一个三角形对象 triangle 作为参数。

    • 使用重心坐标法生成三角形内的随机点,并返回该点的坐标。

  4. triangulate(polygon) 函数 :

    • 接受一个多边形对象 polygon 作为参数。

    • 需要实现具体的三角剖分算法,例如 earcut 算法。

    • 返回一个包含多个三角形坐标的数组。

应用示例:将点绘制到 SVG

// 定义多边形
const polygon = {
  points: [
    { x: 100, y: 100 },
    { x: 200, y: 50 },
    { x: 300, y: 150 },
    { x: 250, y: 200 },
    { x: 150, y: 150 },
  ],
};

// 分布 20 个点到多边形内
const points = distributePointsInPolygon(polygon, 20);

// 将点绘制到 SVG 中
// ... 

常见问题解答:为你答疑解惑

  1. 问:可以使用其他三角剖分算法吗?

    答:当然可以!代码示例中使用的 triangulate 函数只是一个示例,你可以根据实际需求选择其他更高效的三角剖分算法,例如 earcut 算法。

  2. 问:如何将生成的点绘制到 SVG 中?

    答:你可以使用 SVG 的 <circle> 元素来表示点,并将 distributePointsInPolygon 函数返回的点坐标应用于 <circle> 元素的 cxcy 属性。

  3. 问:如何控制点的密度?

    答:可以通过调整传递给 distributePointsInPolygon 函数的 numberOfPoints 参数来控制点的密度。numberOfPoints 越大,点密度越高。

  4. 问:这种方法可以应用于其他形状吗?

    答:理论上,只要可以将目标形状进行三角剖分,就可以使用这种方法在其中均匀分布点。

  5. 问:还有其他方法可以实现类似的效果吗?

    答:除了三角剖分和面积加权,还可以使用其他方法,例如 Poisson Disc Sampling,来实现更均匀的点分布效果,但实现起来可能更加复杂。

通过本文,你学习了如何使用 JavaScript 将任意数量的点均匀分布到 SVG 多边形内,并了解了代码实现的细节和常见问题解答。希望这些信息能够帮助你在实际项目中轻松运用这一技巧。

不爱php
不爱php

58 天前

签名 : 智者不入爱河   17       0
评论
站长交流