删除多边形边缘上重复点的最快方法是什么?

时间:2015-09-22 14:46:32

标签: algorithm

如下所示,我有一个包含整数点的多边形:

type
  TPoint = array [1 .. 2] of Integer;
  TPointArray = array of TPoint;

边缘上的点按时钟顺序给出,我想删除中间点(标记为红色)。

例如,给定任意连续3点A,B,C如果B恰好在A和C之间的线上,则可以安全地移除B.

如何快速有效地完成这项工作?

我的Psedu代码是:

procedure RemovePoints(var pt: TPointArray);
var
  i, j, sz, k, u: integer;
  xoffset, yoffset: integer;
begin
  sz := High(pt);
  i := 0;
  while (True) do
  begin
    Inc(i);
    // points represent array index, so can't be negative,
    // we use -1 to mark deletion
    if (pt[i][1] = -1) then continue;
    if (i = 0) then
    begin
      break; // finish a loop
    end;
    j := i + 1;
    if (j > sz) then
    begin
      j := 0;
    end;
    k := j + 1;
    if (k > sz) then
    begin
      k := 0;
    end;
    if ((pt[i][1] - pt[j][1] = pt[j][1] - pt[k][1]) and ((pt[i][2] - pt[j][2] = pt[j][2] - pt[k][2]))) then
    begin
      // remove pt[j];
      pt[j][1] := -1;
    end;
  end;
  // TODO: shrink the array to remove deleted points
end;

Polygon Points on edges

2 个答案:

答案 0 :(得分:3)

浏览列表并考虑相邻点的三元组 p q r 。确定前向向量 pq qr 并检查它们是否共线。如果是这样,如果它们面向同一方向,请标记删除点。

在第二遍中,过滤掉标记的点。

如果两个向量的叉积是空向量,则它们是共线的。平面中矢量的叉积仅具有垂直于该平面的一个分量。所以检查:

\b

如果你想确保不删除狭长柄的尖点,请检查矢量的点积是否为正:

pq.x * qr.y - pq.y * qr.x == 0

因为你有整数坐标,所以这些检查应该很简单。

这是一个使用您的命名法和类型的解决方案。它在单独的数组中跟踪要删除的节点。 (您无法使用虚拟值标记坐标,因为在确定是否删除下一个节点时仍需要坐标完整。)

pq.x * qr.x + pq.y * qr.y > 0

答案 1 :(得分:0)

我们已经知道我们可以使用斜率截距方程完美地定义一条线。这意味着我们还可以使用斜率和该线所经过的一个点唯一地定义一条线。

从多边形点列表的第一个点开始,计算通过第一个点和下一个点的线的斜率。这是您的第一个斜率值。将此值存储为currentSlope。创建newPointList以存储新的边缘点。下一个:

  1. 从第三点开始迭代所有点;
  2. 如果第二点和第三点的斜率与currentSlope相同
    1. 这意味着第二个点与第一个和第三个点在同一行,所以跳过这一点
    2. continue循环回到第1步。
  3. 如果第二点和第三点的斜率与currentSlope不同
    1. 这意味着由第一和第二点定义的边缘与由第二和第三点定义的边缘不同。
    2. 将第一个和第二个点存储在newPointList中,并将currentSlope的值更新为第二个和第三个点之间的斜率。
  4. 当迭代结束时,newPointList将只包含多边形的顶点。