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

如何在JavaScript/D3中移除多边形边上的冗余共线点

精简多边形点集:移除边上共线中间点

问题说明

给定一个多边形的点集,部分点位于多边形某条边的两个端点之间且与端点共线,需要编写函数剔除这些冗余点,得到仅保留顶点的精简多边形点集。

实现思路

核心是判断每个点是否为非顶点的共线中间点:

  • 对每个点(首尾点按闭合多边形逻辑循环处理),取其前一个点和后一个点,计算三点叉乘:叉乘为0则说明三点共线
  • 验证当前点是否落在前后两点构成的线段范围内:通过坐标极值范围或点积方向判断
  • 仅保留不满足上述共线中间点条件的点(即多边形顶点)

代码实现

多边形点集精简函数

function cleanPolygonPoints(points) {
  if (points.length < 3) return [...points]; // 少于3个点直接返回

  const cleaned = [];
  const len = points.length;

  for (let i = 0; i < len; i++) {
    const prevPoint = points[(i - 1 + len) % len]; // 前一个点,闭合循环处理
    const currPoint = points[i];
    const nextPoint = points[(i + 1) % len]; // 后一个点,闭合循环处理

    // 计算叉乘,判断三点是否共线
    const crossProduct = (nextPoint[0] - prevPoint[0]) * (currPoint[1] - prevPoint[1]) - 
                         (nextPoint[1] - prevPoint[1]) * (currPoint[0] - prevPoint[0]);

    // 叉乘不为0,说明不是共线中间点,保留
    if (crossProduct !== 0) {
      cleaned.push(currPoint);
      continue;
    }

    // 叉乘为0时,验证是否在前后点的线段范围内
    const isBetweenX = (currPoint[0] - prevPoint[0]) * (currPoint[0] - nextPoint[0]) <= 0;
    const isBetweenY = (currPoint[1] - prevPoint[1]) * (currPoint[1] - nextPoint[1]) <= 0;
    // 不在线段中间(比如是端点重合)则保留
    if (!isBetweenX || !isBetweenY) {
      cleaned.push(currPoint);
    }
    // 否则跳过该共线中间点
  }

  // 处理重复的首尾闭合点
  if (cleaned.length > 1 && JSON.stringify(cleaned[0]) === JSON.stringify(cleaned[cleaned.length - 1])) {
    cleaned.pop();
  }
  // 确保多边形闭合,添加首尾一致的点
  cleaned.push(cleaned[0]);
  return cleaned;
}

D3.js 可视化示例

<!DOCTYPE html>
<html>
<head>
  <script src="https://d3js.org/d3.v7.min.js"></script>
  <style>
    .container { display: flex; gap: 20px; margin: 20px; }
    svg { border: 1px solid #ddd; }
    .raw-path { fill: rgba(255, 99, 71, 0.2); stroke: #ff6347; stroke-width: 2; }
    .cleaned-path { fill: rgba(32, 178, 170, 0.2); stroke: #20b2aa; stroke-width: 2; }
    .point { r: 3; fill: #333; }
  </style>
</head>
<body>
  <div class="container">
    <div>
      <h3>原始多边形</h3>
      <svg id="rawSvg" width="400" height="400"></svg>
    </div>
    <div>
      <h3>精简后多边形</h3>
      <svg id="cleanedSvg" width="400" height="400"></svg>
    </div>
  </div>

  <script>
    // 示例原始点集
    const rawData = [
      [50, 50], [100, 100], [150, 150], [200, 50], [150, 0], [100, -50], [50, 0], [0, 50], [50, 50]
    ];
    // 获取精简后的点集
    const cleanedData = cleanPolygonPoints(rawData);

    // 通用绘图函数
    function drawPolygon(svgId, data, pathClass) {
      const svg = d3.select(`#${svgId}`);
      const scaleX = d3.scaleLinear().domain([-100, 300]).range([50, 350]);
      const scaleY = d3.scaleLinear().domain([-100, 200]).range([350, 50]);

      // 生成路径
      const lineGenerator = d3.line()
        .x(d => scaleX(d[0]))
        .y(d => scaleY(d[1]));

      svg.append("path")
        .attr("class", pathClass)
        .attr("d", lineGenerator(data));

      // 绘制点
      svg.selectAll(".point")
        .data(data)
        .enter()
        .append("circle")
        .attr("class", "point")
        .attr("cx", d => scaleX(d[0]))
        .attr("cy", d => scaleY(d[1]));
    }

    // 绘制原始和精简后的多边形
    drawPolygon("rawSvg", rawData, "raw-path");
    drawPolygon("cleanedSvg", cleanedData, "cleaned-path");
  </script>
</body>
</html>

示例效果

  • 原始点集包含多个共线中间点(比如[50,50]→[100,100]→[150,150]这三个共线点)
  • 精简后仅保留线段的两个端点[50,50]和[150,150],其余共线中间点被剔除,多边形形状不变但点集更简洁

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:25:12