Condense a set of points of a polygon into a shorter set of points

use*_*1_1 2 matlab polygon

I have the following polygon which is just a set of 2D points as follows:-

poly0=[80    60
    90    60
   100    60
   110    60
   110    50
   120    50
   130    50
   140    50
   150    50
   160    50
   170    50
   180    50
   190    50
   200    50
   210    50
   210    60
   210    70
   210    80
   210    90
   220    90
   220   100
   210   100
   210   110
   200   110
   200   120
   190   120
   180   120
   180   130
   170   130
   160   130
   150   130
   140   130
   130   130
   130   120
   120   120
   110   120
   110   110
   100   110
   100   100
    90   100
    90    90
    90    80
    90    70
    80    70
    80    60];
Run Code Online (Sandbox Code Playgroud)

Now I can plot it using.

>> line(poly0(:,1), poly0(:,2),'Color','k','LineWidth',3,'LineStyle',':');
Run Code Online (Sandbox Code Playgroud)

This clearly shows one thing that my original set of polygon points is highly redundant. Basically, multiple points lying on the same straight line are enumerated above which is not needed. I could start checking each pair of points and if they are on the same straight line I could remove them. But that would mean using many for loops. I cannot come up with a smart vectorized way.

How do I get a new set of points which is much shorter in size than the previous but which still represents the exact same polygon? I should only have as many points as there are vertices in the polygon. So in other words how to find the vertices from the above data set in a quick way?

PS: Here the vertex angles are 90 degrees, but if you give a solution don't try to exploit that fact. I want a more general answer.

Cri*_*ngo 5

现有的两个答案有很大的缺点:

  • 只有当后续点之间的距离完全相同时,Durkee的方法才有效。点必须具有完全可表示为浮点值的坐标,以便可以找到直线上后续点之间的距离相同。如果点不等距,则该方法不执行任何操作。另外,多边形的起点和终点不会一起检查,因此,如果在多边形的起点/终点形成一条直线,那么将留下太多的点。

  • ShadowMan的方法更好,因为距离不必相同,并且正确处理了多边形起点/终点的线。但是,它也使用浮点相等比较,通常无法正常工作。只有使用整数坐标,此方法才能正常工作。此外,它使用vecnorm(做平方根)和除法(相对于此处显示的方法而言)都是相对昂贵的操作。

要查看三个点是否形成一条直线,可以使用简单的算术规则。假设我们有点p0p1p2。从载体p0p1和从矢量p0p2形成平行四边形,其面积可以通过计算的基础的两个向量的叉积(在图2D中,叉积被理解为使用z=0,具有所得到的向量x=0y=0,只有z值是有用的;因此,我们假设产生一个标量值的2D叉积)。可以如下计算:

v1 = p1 - p0;
v2 = p2 - p0;
x = v1(1)*v2(2) - v1(2)*v2(1);
Run Code Online (Sandbox Code Playgroud)

x如果两个向量平行,则叉积为零,这意味着三个点是共线的。但是,由于浮点算术不精确,因此对于等于0的相等性测试必须具有一定的容差。我在这里使用1e-6作为公差。使用的值比点之间的距离小几个数量级。

给定一组输入点p,我们可以使用以下方法找到角点:

v1 = p1 - p0;
v2 = p2 - p0;
x = v1(1)*v2(2) - v1(2)*v2(1);
Run Code Online (Sandbox Code Playgroud)

请注意,如果两个连续的点具有相同的坐标(即向量之一的长度为零),则该叉积测试将失败。如果数据可能有重复的点,则有必要进行额外的测试。

这是这三种方法的结果。我创建了一个具有非平凡坐标且顶点间距不相等的多边形。我还将开始/结束间隙放在一条直线边缘的中间。这些特性旨在显示其他两种方法的缺点。

三种方法的比较

这是我用来生成图形的代码:

p1 = p;                                  % point 1
p0 = circshift(p1,1);                    % point 0
v1 = p1 - p0;                            % vector from point 0 to 1
v2 = circshift(p1,-1) - p0;              % vector from point 0 to 2
x = v1(:,1).*v2(:,2) - v1(:,2).*v2(:,1); % cross product
idx = abs(x) > 1e-6;                     % comparison with tolerance
p = p(idx,:);                            % corner points
Run Code Online (Sandbox Code Playgroud)