The method of judging the point within the polygon is realized by matlab (the point is within the convex hull and any shape is judged)

Conventional statement: I have no relevant engineering application experience, and I only write this blog purely because I am interested in related algorithms. So if there are mistakes, welcome to correct them in the comment area, thank you very much. This article mainly focuses on the implementation of the algorithm. I have no experience in practical applications and other issues, so I will not involve it anymore.

0 Preface

This article briefly talks about the methods commonly used by computers to determine whether a point is within a polygon. This practical application is quite common, such as purely geometric judgment, or selecting a range to see if the data exceeds this range.

When we judge whether a point is within a polygon, we usually first identify the polygonal figure, and then see if the point is within the range of the recognized figure. But for very complex graphics, it is not easy to draw conclusions at once, and this kind of graphics-based algorithm is actually not efficient and is not suitable for computer calculations.

The commonly used algorithm for judging whether a point is within a polygon is related to the variable n of the polygon, and is usually on the order of O(n), so in fact, there is not much difference between everyone, and it depends on who can optimize better. But for convex polygons, the bisection algorithm can be used to reduce the computational complexity to the O(logn) level, which will be covered later.

If you have time in the future, I am going to try to write an article on judging whether a point is in a three-dimensional or high-dimensional polyhedron ( without filling the hole ).

The blogs and papers referenced in this article are as follows:

[1] Convex polygon (computational geometry, judging whether a point is within a polygon, dichotomy)
https://www.cnblogs.com/yym2013/p/3673616.html
[2] Algorithm for judging a point within a polygon (Winding Number detailed explanation )
https://www.codenong.com/cs106265948/
[3]Hormann K, Agathos A. The point in polygon problem for arbitrary polygons[J]. Computational geometry, 2001, 20(3): 131-144.

1 Ray intersection method (Crossing Number)

This method is called the ray method or the odd-even rule method. The principle is to shoot a ray outward from the point P. If the number of intersections between the ray and the polygon is an odd number, the point P is inside the polygon.

Imagine a soap bubble. If you want to get out of the soap bubble, you must go through the soap bubble once. If two soap bubbles are passed through, one in and one out equals no passing.
Please add a picture description
Usually for the sake of simplicity, the ray is directly chosen as the +x direction, that is, the direction to the right.

The general optimization ideas are as follows:
1. Roughly define the range of a polygon. If the point exceeds this range, there is no need to judge again, and it is directly judged as not in the graph.
2 For the line segment that intersects the ray in the +x direction, its y range must be at both ends of the ray. That is to say, if the line segment is directly above the ray, or the line segment is directly below the ray, there is no need to calculate the intersection point, because it is impossible to intersect.
3 The line segment that intersects the ray in the +x direction cannot be on the left side of the ray.
Please add a picture description

This method looks very simple, but there are still some details that need to be deducted. For example, when the edge line is also a horizontal line, how to calculate the intersection point? When the point falls on the sideline, how to calculate the intersection point? When the sideline is exactly a horizontal line, and the points also fall on this sideline, how many intersections are counted? Won't you get a bug that intersects two edges when the point's ray goes right through the polygon vertex?

Regarding these problems, my approximate solution is: set a concept of edge point, which is specially used to judge whether the point is on the edge. If the point just falls on the sideline of the horizontal line, it will no longer calculate whether it intersects, and directly treat it as a point on the sideline. For the judgment of the intersection point, use the method of one end being less than or equal to and the other end being less than to avoid double counting. And because there are errors in the calculation, an error band needs to be added to the calculated intersection point xc to prevent misjudgment.

Not much to say, the matlab program is as follows:

clear
clc
close all
%多边形定义(连线必须按照首尾相接的顺序)
BD=[0,0;0,-1;1,0;2,-1;2,0;2,1;2,2;1,2;1,1;0,1];%凹多边形
%BD=[0,-1;0,-2;1,-1;2,-2;2,-1;2,0;2,3;-1,3;-1,1;...
%    3,1;3,1.5;0,1.5;0,2.5;1,2.5;1,0;0,0];%凹多边形,而且自相交
%BD=[0,1;-1,0;-1,-1;0,-1;1,-1;1,0];%凸多边形
%要判断的点
[X,Y]=meshgrid(-5:0.1:5,-5:0.1:5);
xy2=[X(:),Y(:)];

[IsInPoly,IsOnBD]=IfInPoly1(BD,xy2);

figure()
hold on
plot(BD(:,1),BD(:,2))
scatter(xy2(:,1),xy2(:,2),24,IsInPoly+2*IsOnBD,'Marker','.')
%scatter(xy2(:,1),xy2(:,2),24,or(IsInPoly,IsOnBD),'Marker','.');%不显示边线

%后置函数
function [IsInPoly,IsOnBD]=IfInPoly1(BD,xy2)
%输出逻辑索引(IsInPoly表示在内部,IsOnBD表示在多边形边界上)
%BD是多边形边界,存在顺序,两列。xy2是点的坐标,两列。
%方法1,射线法
if (BD(1,1)~=BD(end,1)) || (BD(1,2)~=BD(end,2))
    BD2=[BD;BD(1,:)];
else %给出的边界已经收尾相接
    BD2=BD;
end
%删除边界中相邻重复的点
IsSame=and(BD2(1:end-1,1)==BD2(2:end,1),BD2(1:end-1,2)==BD2(2:end,2));
BD2([IsSame;false],:)=[];
NB=size(BD2,1)-1;
NP=size(xy2,1);

IsInPoly=false(NP,1);%true(NP,1);%false(NP,1);
IsOnBD=false(NP,1);%是否在边线上
%判断整个边线的大概范围
min_X_BD=min(BD(:,1));
max_X_BD=max(BD(:,1));
min_Y_BD=min(BD(:,2));
max_Y_BD=max(BD(:,2));
%做+x方向的射线
for kp=1:NP
    %如果这个点的xy超过整个边线的xy,则肯定不在边线内
    xy_k=xy2(kp,:);
    xp=xy_k(1);
    yp=xy_k(2);
    if xp<min_X_BD || xp>max_X_BD || yp<min_Y_BD || yp>max_Y_BD
        %IsInPoly(kp)=false;
        continue
    end
    %循环每一条边
    NCross=0;%初始化交点数量
    for kB=1:NB
        xB1=BD2(kB,1);xB2=BD2(kB+1,1);
        yB1=BD2(kB,2);yB2=BD2(kB+1,2); 
        %如果在+x方向上相交,在点一定在线的左边
        if max([xB1,xB2])<xp
            continue %所以点在线右侧的情况无需计算
        end
        %判断是否在水平的边线上
        if yB1==yp && yB2==yp && ( min([xB1,xB2])<=xp && max([xB1,xB2])>=xp)
            IsOnBD(kp)=true;%如果点在水平线段上,则证明点在边缘
            break %停止循环
        end
        %判断是否是某个顶点
        if (xp==xB1 && yp==yB1) || (xp==xB2 && yp==yB2) 
            IsOnBD(kp)=true;%如果点是某个边缘顶点,则证明点在边缘
            break
        end
        %如果射线穿过这个边,则y值一定介于这个边的两个y值中间
        if (yB1<=yp && yp<yB2) || (yB2<=yp && yp<yB1) 
            %如果在+x方向上相交,则交点一定在xp的右边
            yc=yp;
            xc=xB1+(xB2-xB1)/(yB2-yB1)*(yc-yB1);%计算射线与边的交点(xc,yc)
            if (xc-xp)>4*eps %由于计算会导致xc有一定的误差,所以保守估算为4*eps
                NCross=NCross+1;%证明的确相交,交点+1
            end
            %再次判断是否在边线上
            if abs(xc-xp)<=4*eps && abs(yc-yp)<=4*eps %这里因为也涉及到xc,所以也设置了一个误差带
                IsOnBD(kp)=true;%如果交点xc就是点xp,则证明点在线上
                break
            end
        end
        
    end
    %根据相交点数的奇偶性判断是否在多边形内
    if ~IsOnBD(kp) && mod(NCross,2)
        IsInPoly(kp)=true;%如果是奇数,则证明在多边形内
    end
end
end

Note: Here are two results of IsInPoly for points within the boundary and IsOnBD for points on the boundary of the polygon. If you need to merge, you can use or(IsInPoly, IsOnBD) to merge the results.

The calculation results are as follows:
Please add a picture description

2 Winding Number

Surrounding number method is similar to intersecting number method, both lead out a ray. However, the winding number no longer calculates the specific intersection point, but judges whether the intersecting line segment passes through the ray upwards or downwards through the ray.

Please add a picture description
As an example, let’s use the picture in the previous chapter as an example. But here the line segments are given directions. We define that going up through the ray (the point on the left side of the line segment), the wrapping number is +1, and going down the ray (pointing on the right side of the line segment), the wrapping number is -1. Finally, the number of windings is added, equal to 0, indicating that the point is outside the polygon, and not equal to 0, indicating that the point is inside the polygon.

The matlab program for this method is as follows:

clear
clc
close all
%多边形定义(连线必须按照首尾相接的顺序)
BD=[0,0;0,-1;1,0;2,-1;2,0;2,1;2,2;1,2;1,1;0,1];%凹多边形
%BD=[0,-1;0,-2;1,-1;2,-2;2,-1;2,0;2,3;-1,3;-1,1;...
%    3,1;3,1.5;0,1.5;0,2.5;1,2.5;1,0;0,0];%凹多边形,而且自相交
%BD=[0,1;-1,0;-1,-1;0,-1;1,-1;1,0];%凸多边形
%要判断的点
[X,Y]=meshgrid(-5:0.1:5,-5:0.1:5);
xy2=[X(:),Y(:)];

[IsInPoly,IsOnBD]=IfInPoly2(BD,xy2);

figure()
hold on
plot(BD(:,1),BD(:,2))
scatter(xy2(:,1),xy2(:,2),24,IsInPoly+2*IsOnBD,'Marker','.')
%如果考虑边界情况,则把两个结果合并
%IsInPoly=or(IsInPoly,IsOnBD);

function [IsInPoly,IsOnBD]=IfInPoly2(BD,xy2)
%输出逻辑索引(IsInPoly表示在内部,IsOnBD表示在多边形边界上)
%BD是多边形边界,存在顺序,两列。xy2是点的坐标,两列。
%方法2 winding number 环绕数法
%将边界收尾相接
if (BD(1,1)~=BD(end,1)) || (BD(1,2)~=BD(end,2))
    NB=size(BD,1);
    BD2=[BD;BD(1,:)];
else %给出的边界已经收尾相接
    NB=size(BD,1)-1;
    BD2=BD;
end
%删除边界中相邻重复的点
IsSame=and(BD2(1:end-1,1)==BD2(2:end,1),BD2(1:end-1,2)==BD2(2:end,2));
BD2([IsSame;false],:)=[];
NB=size(BD2,1)-1;
NP=size(xy2,1);

IsInPoly=false(NP,1);%true(NP,1);%false(NP,1);
IsOnBD=false(NP,1);%是否在边线上
%判断整个边线的大概范围
min_X_BD=min(BD(:,1));
max_X_BD=max(BD(:,1));
min_Y_BD=min(BD(:,2));
max_Y_BD=max(BD(:,2));
%做+x方向的射线,来判定环绕数
for kp=1:NP
    %如果这个点的xy超过整个边线的xy,则肯定不在边线内
    xy_k=xy2(kp,:);
    xp=xy_k(1);
    yp=xy_k(2);
    if xp<min_X_BD || xp>max_X_BD || yp<min_Y_BD || yp>max_Y_BD
        continue
    end
    %循环每一条边
    NWinding=0;%初始化环绕数
    for kB=1:NB
        xB1=BD2(kB,1);xB2=BD2(kB+1,1);
        yB1=BD2(kB,2);yB2=BD2(kB+1,2);
        %如果在+x方向上相交,在点一定在线的左边
        if max([xB1,xB2])<xp
            continue %所以点在线右侧的情况无需计算
        end
        %判断是否在水平的边线上
        if yB1==yp && yB2==yp && ( min([xB1,xB2])<=xp && max([xB1,xB2])>=xp)
            IsOnBD(kp)=true;%如果点在水平线段上,则证明点在边缘
            break
        end
        %判断是否是某个顶点
        if (xp==xB1 && yp==yB1) || (xp==xB2 && yp==yB2) 
            IsOnBD(kp)=true;%如果点是某个边缘顶点,则证明点在边缘
            break
        end
        %如果射线穿过这个边,则y值一定介于这个边的两个y值中间
        if (yB1<=yp && yp<yB2) || (yB2<=yp && yp<yB1) 
            %如果在+x方向上相交,则开始判定点在向量的左边还是右边(向量的左右,不是前面整个几何意义的左右)
            if yB2>yB1 %这个边的方向向上
                CrossP=(xB2-xB1)*(yp-yB1)-(xp-xB1)*(yB2-yB1);%计算向量差积,判定点在向量左右
                if CrossP>0 %点在向量左侧
                    NWinding=NWinding+1;
                end
            elseif yB2<yB1 %这个边的方向向下
                CrossP=(xB2-xB1)*(yp-yB1)-(xp-xB1)*(yB2-yB1);%计算向量差积,判定点在向量左右
                if CrossP<0 %点在向量右侧
                    NWinding=NWinding-1;
                end
            else %这个边水平,不计入相交情况
                CrossP=-1;
            end
            %再次判断是否在边线上
            if abs(CrossP)<=4*eps %理论上CrossP==0是在边线上,但这里因为涉及到误差计算,所以加了一个4eps。
                IsOnBD(kp)=true;
                %break
            end
        end
        
    end
    %如果NWinding不是0,则证明在多边形内
    if ~IsOnBD(kp) && NWinding
        IsInPoly(kp)=true;
    end
end

end

The advantage of this method is that, for self-intersecting graphs, the wrapping number method can distinguish overlapping regions. For example, when the encircling number is stipulated to be equal to 2, if the ray method is used, it will be judged that the point is not in the graph, but the encircling number method can distinguish this area.
(If the wrapping number is specified as an even number, the point is outside the graph, and if the wrapping number is odd, the point is inside the graph, then the wrapping number method and the ray intersection method are equivalent.)

For example, the figure below shows a self-intersecting graph, when the intersection method and the surround number method are used at the same time, how the two deal with the overlapping part. Ordinary graphics will not appear self-intersection, but if there is a relatively high demand for self-intersection, you can choose the required algorithm.
Please add a picture description
Of course, the surround number method also avoids the use of division because it does not need to calculate the specific intersection point. If you are also sensitive to division, you can try to use the surround number method.

3 angle method (corner method)

3.1 Angle addition method

This method is easier to understand, that is, if the point is inside the graph, the angle of all rays added up is equal to 360°.
Please add a picture description
But if the graph is a concave polygon, this method also needs to define the positive and negative angles. As shown in the figure above, an angle that increases in the same direction is defined as positive, and an angle that suddenly reverses in this direction is defined as negative. The specific determination method is determined by the cross product of vectors.

公司公式文:
θ = ∑ ω i = ∑ 1 n − 1 acos ( v 1 ⃗ ⋅ v 2 ⃗ ∥ v 1 ⃗ ∥ ∥ v 2 ⃗ ∥ ) ∗ sign ( v 1 ⃗ × v 2 ⃗ ) \theta=\ sum{\omega_i}=\sum_{1}^{n-1}{acos(\frac{\vec{v_1} \cdot \vec{v_2}}{\left \| \vec{v_1}\right \| \left \| \vec{v_2}\right \|} ) *sign(\vec{v_1}×\vec{v_2})}i=ohi=1n1acos(v1 v2 v1 v2 )sign(v1 ×v2 )

Here v1 and v2 are two rays from point p to the two ends of the line segment.
The basic principle and results here are the same as the surround number method, but because it involves the calculation of acos, the speed is usually relatively slow, and the improvement method in the following section will talk about how to speed it up.

The specific procedure is as follows:

clear
clc
close all
%多边形定义(连线必须按照首尾相接的顺序)
BD=[0,0;0,-1;1,0;2,-1;2,0;2,1;2,2;1,2;1,1;0,1];%凹多边形
%BD=[0,-1;0,-2;1,-1;2,-2;2,-1;2,0;2,3;-1,3;-1,1;...
%    3,1;3,1.5;0,1.5;0,2.5;1,2.5;1,0;0,0];%凹多边形,而且自相交
%BD=[0,1;-1,0;-1,-1;0,-1;1,-1;1,0];%凸多边形
%要判断的点
[X,Y]=meshgrid(-5:0.1:5,-5:0.1:5);
xy2=[X(:),Y(:)];
%xy2=[0.5,2];

[IsInPoly,IsOnBD]=IfInPoly3(BD,xy2);

figure()
hold on
plot(BD(:,1),BD(:,2))
scatter(xy2(:,1),xy2(:,2),24,IsInPoly+2*IsOnBD,'Marker','.')

function [IsInPoly,IsOnBD]=IfInPoly3(BD,xy2)
%方法3 计算角度法
%将边界收尾相接
if (BD(1,1)~=BD(end,1)) || (BD(1,2)~=BD(end,2))
    NB=size(BD,1);
    BD2=[BD;BD(1,:)];
else %给出的边界已经收尾相接
    NB=size(BD,1)-1;
    BD2=BD;
end
%删除边界中相邻重复的点
IsSame=and(BD2(1:end-1,1)==BD2(2:end,1),BD2(1:end-1,2)==BD2(2:end,2));
BD2([IsSame;false],:)=[];
NB=size(BD2,1)-1;
NP=size(xy2,1);

IsInPoly=false(NP,1);%true(NP,1);%false(NP,1);
IsOnBD=false(NP,1);%是否在边线上
%判断整个边线的大概范围
min_X_BD=min(BD(:,1));
max_X_BD=max(BD(:,1));
min_Y_BD=min(BD(:,2));
max_Y_BD=max(BD(:,2));
%做+x方向的射线,来判定环绕数
for kp=1:NP
    %如果这个点的xy超过整个边线的xy,则肯定不在边线内
    xy_k=xy2(kp,:);
    xp=xy_k(1);
    yp=xy_k(2);
    if xp<min_X_BD || xp>max_X_BD || yp<min_Y_BD || yp>max_Y_BD
        continue
    end
    %判断是否是某个顶点
    if any(and(xp==BD2(:,1),yp==BD2(:,2)))
        %IsOnBD(kp)=true;%如果点是某个边缘顶点,则证明点在边缘
        IsOnBD(kp)=true;
        continue
    end
    %循环每一条边
    AngleSum=0;%初始化环绕数
    for kB=1:NB

        xB1=BD2(kB,1);xB2=BD2(kB+1,1);
        yB1=BD2(kB,2);yB2=BD2(kB+1,2);
        v1=[xB1-xp,yB1-yp];v2=[xB2-xp,yB2-yp];
        CosAngle=dot(v1,v2)/norm(v1)/norm(v2);
        if abs(CosAngle+1)<4*eps
            IsOnBD(kp)=true;
            break
        end
        Sign=sign(det([v1(1),v2(1);v1(2),v2(2)]));
        AngleSum=acos(CosAngle)*Sign+AngleSum;
        %AngleList(kB)=acos(CosAngle)*Sign/pi*180;
    end
    if abs(AngleSum)/2/pi>(1-1e-5)
        IsInPoly(kp)=true;
    end
end
IsInPoly=and(IsInPoly,~IsOnBD);%对于那些又在边线上又边线内的,判定为在边线上。

end

3.2 Improved angle method (matlab comes with inpolygon function method)

Matlab comes with the inpolygon() function to determine whether a point is within a polygon.

Here we no longer specifically calculate the angle, but use the relationship between the rays x and y to make a rough judgment. First connect the points to vertices on the edge to form a set of rays. Divide the ray direction into four quadrants: upper right ↗, upper left ↖, lower left ↙, and lower right ↘, and assign 4 numbers of 0, 1, 2, and 3 respectively. Then judge the final angle based on the changes of these numbers.

For the specific method, please refer to the specific code of the matlab function inpolygon, or see the paper The point in polygon problem for arbitrary polygons, here I will not show my ugliness and re-edit it myself.

The specific usage method is as follows

clear
clc
close all
%多边形定义(连线必须按照首尾相接的顺序)
BD=[0,0;0,-1;1,0;2,-1;2,0;2,1;2,2;1,2;1,1;0,1];%凹多边形
%BD=[0,-1;0,-2;1,-1;2,-2;2,-1;2,0;2,3;-1,3;-1,1;...
%    3,1;3,1.5;0,1.5;0,2.5;1,2.5;1,0;0,0];%凹多边形,而且自相交
%BD=[0,1;-1,0;-1,-1;0,-1;1,-1;1,0];%凸多边形
%要判断的点
[X,Y]=meshgrid(-5:0.1:5,-5:0.1:5);
xy2=[X(:),Y(:)];

%方法6 matlab自带方法
[IsInPoly,IsOnBD]=inpolygon(xy2(:,1),xy2(:,2),BD(:,1),BD(:,2));

figure()
hold on
plot(BD(:,1),BD(:,2))
scatter(xy2(:,1),xy2(:,2),24,IsInPoly+2*IsOnBD,'Marker','.')

I am using the 2019b version, and there are several sideline points that have not been identified, which is probably the result of no error introduced. But it runs fast.
Please add a picture description

4 Cross product method (only for convex polygons)

The idea of ​​the cross product method comes from the angle method. For a convex polygon, if a point is within the polygon, connect the point to each vertex of the polygon to form a series of vectors, and the angles between these vectors must be acute angles.
Please add a picture description
For example, in the left picture above, the cross product of P1 and P2 is positive, and the cross product of P2 and P3 is also positive. Similarly, P3 and P4, P4 and P5, P5 and P1 are all positive. But for the picture on the right, the cross product of P5 and P1 is a negative value, indicating that the point is outside the polygon.

code show as below:

clear
clc
close all
%多边形定义(连线必须按照首尾相接的顺序)
%BD=[0,0;0,-1;1,0;2,-1;2,0;2,1;2,2;1,2;1,1;0,1];%凹多边形
%BD=[0,-1;0,-2;1,-1;2,-2;2,-1;2,0;2,3;-1,3;-1,1;...
%    3,1;3,1.5;0,1.5;0,2.5;1,2.5;1,0;0,0];%凹多边形,而且自相交
BD=[0,1;-1,0;-1,-1;0,-1;1,-1;1,0];%凸多边形
%要判断的点
[X,Y]=meshgrid(-5:0.1:5,-5:0.1:5);
xy2=[X(:),Y(:)];
%xy2=[0.8,0.8];

IsInPoly=IfInPoly4(BD,xy2);

figure()
hold on
plot(BD(:,1),BD(:,2))
%scatter(xy2(:,1),xy2(:,2),24,IsInPoly+2*IsOnBD,'Marker','.')
scatter(xy2(:,1),xy2(:,2),24,IsInPoly,'Marker','.')

function IsInPoly=IfInPoly4(BD,xy2)
%方法4 计算叉积法
%将边界收尾相接
if (BD(1,1)~=BD(end,1)) || (BD(1,2)~=BD(end,2))
    NB=size(BD,1);
    BD2=[BD;BD(1,:)];
else %给出的边界已经收尾相接
    NB=size(BD,1)-1;
    BD2=BD;
end
%删除边界中相邻重复的点
IsSame=and(BD2(1:end-1,1)==BD2(2:end,1),BD2(1:end-1,2)==BD2(2:end,2));
BD2([IsSame;false],:)=[];
NB=size(BD2,1)-1;
NP=size(xy2,1);

IsInPoly=false(NP,1);%true(NP,1);%false(NP,1);
IsOnBD=false(NP,1);%是否在边线上
%判断整个边线的大概范围
min_X_BD=min(BD(:,1));
max_X_BD=max(BD(:,1));
min_Y_BD=min(BD(:,2));
max_Y_BD=max(BD(:,2));
%做+x方向的射线,来判定环绕数
for kp=1:NP
    %如果这个点的xy超过整个边线的xy,则肯定不在边线内
    xy_k=xy2(kp,:);
    xp=xy_k(1);
    yp=xy_k(2);
    if xp<min_X_BD || xp>max_X_BD || yp<min_Y_BD || yp>max_Y_BD
        continue
    end
    %判断是否是某个顶点
    if any(and(xp==BD2(:,1),yp==BD2(:,2)))
        %IsOnBD(kp)=true;%如果点是某个边缘顶点,则证明点在边缘
        IsInPoly(kp)=true;
        continue
    end
    %循环每一条边
    ArrowDir=zeros(NB,1);%初始化叉积方向
    for kB=1:NB
        xB1=BD2(kB,1);xB2=BD2(kB+1,1);
        yB1=BD2(kB,2);yB2=BD2(kB+1,2);
        v1=[xB1-xp,yB1-yp,0];v2=[xB2-xp,yB2-yp,0];
        CrossV=cross(v1,v2);
        ArrowDir(kB)=CrossV(3);
    end
    %根据最大角度和最小角度之差
    if all(ArrowDir>=0) || all(ArrowDir<=0)
        IsInPoly(kp)=true;
    end
end

end

The result is as follows:
Please add a picture description
It can be seen that for convex polygons, this algorithm is still no problem. But for concave polygons, this method will produce wrong results. So when using this method, you must pay attention to whether it is a convex polygon.

5 grid method

As the name suggests, the grid method is because the polygonal shape is too complex to be judged simply. Then you can first draw many grids inside the polygon, and then judge whether the points are in the grid in turn.

The advantage of the rectangular grid is that the judgment speed is fast, but the judgment of the hypotenuse is more complicated. It is possible to cause part of the rectangle to be inside the polygon and part to be outside the polygon.

A simple judgment is made here with a triangular mesh. The first is to divide the triangle. Here I use the delaunayTriangulation() function that comes with matlab.
Judging whether a point is within a triangle can be obtained by solving a binary quadratic equation with two vectors.
Please add a picture description
The position of this point can be determined by a u+b v. If a, b, and a+b are all between 0 and 1, the point must be within the triangle.

The specific procedure is as follows:

clear
clc
close all
%多边形定义(连线必须按照首尾相接的顺序)
BD=[0,0;0,-1;1,0;2,-1;2,0;2,1;2,2;1,2;1,1;0,1];%凹多边形
%BD=[0,-1;0,-2;1,-1;2,-2;2,-1;2,0;2,3;-1,3;-1,1;...
%    3,1;3,1.5;0,1.5;0,2.5;1,2.5;1,0;0,0];%凹多边形,而且自相交
%BD=[0,1;-1,0;-1,-1;0,-1;1,-1;1,0];%凸多边形
%要判断的点
[X,Y]=meshgrid(-5:0.1:5,-5:0.1:5);
xy2=[X(:),Y(:)];

IsInPoly=IfInPoly5(BD,xy2);

figure()
hold on
plot(BD(:,1),BD(:,2))
scatter(xy2(:,1),xy2(:,2),24,IsInPoly,'Marker','.')


function IsInPoly=IfInPoly5(BD,xy2)
%方法5 三角形网格剖分法
%如果边界收尾相接,则取消
if (BD(1,1)==BD(end,1)) && (BD(1,2)==BD(end,2))
    BD2=BD(1:end-1,:);
else %给出的边界已经收尾相接
    BD2=BD;
end
%删除边界中相邻重复的点
IsSame=and(BD2(1:end-1,1)==BD2(2:end,1),BD2(1:end-1,2)==BD2(2:end,2));
BD2([IsSame;false],:)=[];
NB=size(BD2,1);
NP=size(xy2,1);

IsInPoly=false(NP,1);%true(NP,1);%false(NP,1);
%IsOnBD=false(NP,1);%是否在边线上
%判断整个边线的大概范围
min_X_BD=min(BD2(:,1));
max_X_BD=max(BD2(:,1));
min_Y_BD=min(BD2(:,2));
max_Y_BD=max(BD2(:,2));

%按照边缘三角剖分
C=(1:NB)';
C=[C,[(2:NB)';1]];
DT = delaunayTriangulation(BD2,C);
%剔除落在外面的三角形
IO = isInterior(DT);
CL=DT.ConnectivityList;
CL(~IO,:)=[];
BD2=DT.Points;%点有可能会被网格划分所更新,所以这里重新加载一下
NB=size(BD2,1);

BDx=BD2(:,1);
BDy=BD2(:,2);
%triplot(CL,BDx,BDy)
%得到每个三角形的坐标
TRI_X=BDx(CL);
TRI_Y=BDy(CL);
NT=size(CL,1);
%计算每个三角形的范围
max_TRI_X=max(TRI_X,[],2);
min_TRI_X=min(TRI_X,[],2);
max_TRI_Y=max(TRI_Y,[],2);
min_TRI_Y=min(TRI_Y,[],2);
%计算每个三角形的向量
V1_Sum=[TRI_X(:,2)-TRI_X(:,1),TRI_Y(:,2)-TRI_Y(:,1)];
V2_Sum=[TRI_X(:,3)-TRI_X(:,1),TRI_Y(:,3)-TRI_Y(:,1)];
%开始循环判断
for kp=1:NP
    %如果这个点的xy超过整个边线的xy,则肯定不在边线内
    xy_k=xy2(kp,:);
    xp=xy_k(1);
    yp=xy_k(2);
    if xp<min_X_BD || xp>max_X_BD || yp<min_Y_BD || yp>max_Y_BD
        continue
    end
    %判断是否是某个顶点
    if any(and(xp==BD2(:,1),yp==BD2(:,2)))
        %IsOnBD(kp)=true;%如果点是某个边缘顶点,则证明点在边缘
        IsInPoly(kp)=true;
        continue
    end
    %循环每一三角形
    for kT=1:NT
        if xp<min_TRI_X(kT) || xp>max_TRI_X(kT) || yp<min_TRI_Y(kT) || yp>max_TRI_Y(kT)
            continue %如果超出三角形范围,则直接跳过
        end
        %计算是否在三角形内
        V1=V1_Sum(kT,:);
        V2=V2_Sum(kT,:);
        A=[V1',V2'];
        B=[xp-TRI_X(kT,1);yp-TRI_Y(kT,1)];
        u12=A\B;
        if max(u12)<=1 && min(u12)>=0 && sum(u12)<=1
            IsInPoly(kp)=true;
            break
        end
    end
end
end

The mesh division results and the final pattern are as follows:
Please add a picture description

6 Dichotomy (O(logn) algorithm)

If the number of sides of the polygon is very large, then using the previous method to calculate, the complexity is O(n) level, and the number of sides to be looped is proportional to the graph. (Although I feel that if the graphics are relatively simple and the optimization is better, then in the ray method and the surround number method, many edges cannot be cycled, and it should not be too slow).

Then the idea of ​​the dichotomy is to gradually narrow the scope and find the area where the point is located. The algorithm diagram is as follows:
Please add a picture description
first take a vertex, and then make rays to other vertices. If the point is within the polygon, then the point must be within this angle range. Then by gradually reducing the range, the final position of the point is determined.
After that, we can use the method of judging that a point is inside a triangle in Chapter 5 to judge whether this point is inside this triangle.

The specific procedure is as follows:

clear
clc
close all
%多边形定义(连线必须按照首尾相接的顺序)
%BD=[0,0;0,-1;1,0;2,-1;2,0;2,1;2,2;1,2;1,1;0,1];%凹多边形
%BD=[0,-1;0,-2;1,-1;2,-2;2,-1;2,0;2,3;-1,3;-1,1;...
%    3,1;3,1.5;0,1.5;0,2.5;1,2.5;1,0;0,0];%凹多边形,而且自相交
BD=[0,1;-1,0;-1,-1;0,-1;1,-1;1,0];%凸多边形
BD=[2.5*cos(0.01:0.01:2*pi)',2*sin(0.01:0.01:2*pi)'];
%要判断的点
[X,Y]=meshgrid(-5:0.1:5,-5:0.1:5);
xy2=[X(:),Y(:)];

IsInPoly=IfInPoly7(BD,xy2);

figure()
hold on
plot(BD(:,1),BD(:,2))
scatter(xy2(:,1),xy2(:,2),24,IsInPoly,'Marker','.')

function IsInPoly=IfInPoly7(BD,xy2)
%方法7 二分法
NP=size(xy2,1);
BD2=BD;
%1初始化输入
%删除边界中相邻重复的点
IsSame=and(BD2(1:end-1,1)==BD2(2:end,1),BD2(1:end-1,2)==BD2(2:end,2));
BD2([IsSame;false],:)=[];
BD=BD2;
%将边界收尾相接
if (BD(1,1)~=BD(end,1)) || (BD(1,2)~=BD(end,2))
    BD2=[BD;BD(1,:)];
else %给出的边界已经收尾相接
    BD2=BD;
end
%删除三点共线情况的点
Is3Line=false(size(BD2,1)-1,1);
for k=2:size(BD2,1)-1
    if det([ BD2(k-1,:)-BD2(k,:) ; BD2(k+1,:)-BD2(k,:) ])==0
        Is3Line(k)=true;%如果三点共线,则叉积等于0
    end
end
BD2([Is3Line;true],:)=[];%删除三点共线的那些点
if det([ BD2(end,:)-BD2(1,:) ; BD2(2,:)-BD2(1,:) ])==0
    BD2(1,:)=[];%刚才循环没有判断第一个点,重新判断一下
end
NB=size(BD2,1);
%如果边的方向是顺时针方向,则变成逆时针排序方向
xy0=BD2(1,:);
v1_t=BD2(2,:)-xy0;
v2_t=BD2(NB,:)-xy0;
if det([v1_t;v2_t])<eps
    BD2=flipud(BD2);%小于0,说明给出的点是顺时针排序的
end

IsInPoly=false(NP,1);
IsOnBD=false(NP,1);%是否在边线上
%判断整个边线的大概范围
min_X_BD=min(BD(:,1));
max_X_BD=max(BD(:,1));
min_Y_BD=min(BD(:,2));
max_Y_BD=max(BD(:,2));
%2确定起始边和终止边
%以第一个点作为射线基准,计算出所有点的射线
vSum=BD2(2:end,:)-ones(NB-1,1)*BD2(1,:);
Nv=size(vSum,1);
for kp=1:NP
    %3优化,减少计算数量
    %如果这个点的xy超过整个边线的xy,则肯定不在边线内
    xy_k=xy2(kp,:);
    xp=xy_k(1);
    yp=xy_k(2);
    if xp<min_X_BD || xp>max_X_BD || yp<min_Y_BD || yp>max_Y_BD
        continue
    end
    %判断是否是某个顶点
    if any(and(xp==BD2(:,1),yp==BD2(:,2)))
        %IsOnBD(kp)=true;%如果点是某个边缘顶点,则证明点在边缘
        IsInPoly(kp)=true;
        continue
    end
    %判断是否在两端射线范围内
    v0_t=xy_k-BD2(1,:);
    v1_t=vSum(1,:);
    v2_t=vSum(Nv,:);
    if det([v1_t;v0_t])>=0 && det([v0_t;v2_t])>=0
        %如果在两个夹角范围内,则开始后续的二分法循环
        n1=1;
        n2=Nv;
    else
        continue
    end
    %4开始用二分法判断是否在区间内
    while n2-n1>1 %当区间大于1的时候,继续二分
        v1_t=vSum(n1,:);
        v2_t=vSum(n2,:);
        n3=fix((n1+n2)/2);
        v3_t=vSum(n3,:);
        
        if det([v1_t;v0_t])>=0 && det([v0_t;v3_t])>=0
            %在第一个区间
            n1=n1;
            n2=n3;
        else %在第二个区间
            n1=n3;
            n2=n2;
        end
    end
    %5二分法结束后,确定该点是否在两个向量所围成的三角形中,
    v1_t=vSum(n1,:);
    v2_t=vSum(n2,:);
    A=[v1_t',v2_t'];
    B=[xp-BD2(1,1);yp-BD2(1,2)];
    u12=A\B;
    if max(u12)<=1 && min(u12)>=0 && sum(u12)<=1
        IsInPoly(kp)=true;%如果点在这个三角形内,则证明点在多边形内
    end
end
end

The final result is as follows:
Please add a picture description

7 between multiple regions

If it involves the relationship between multiple areas, you can use the intersection and difference operations of logical operators to gradually divide the selected area.

For example, the figure below shows the results of each area extraction after the two graphics intersect:
Please add a picture description
the code is as follows:

%多边形定义(连线必须按照首尾相接的顺序)
BD1=[2*cos(0.01:0.01:2*pi)'-1,2*sin(0.01:0.01:2*pi)'];
BD2=[2*cos(0.01:0.01:2*pi)'+1,2*sin(0.01:0.01:2*pi)'];
%要判断的点
[X,Y]=meshgrid(-5:0.1:5,-5:0.1:5);
X=X+randn(size(X))*0.05;
Y=Y+randn(size(Y))*0.05;
xy2=[X(:),Y(:)];

%判断点是否在图形内
IsInPoly1=inpolygon(xy2(:,1),xy2(:,2),BD1(:,1),BD1(:,2));
IsInPoly2=inpolygon(xy2(:,1),xy2(:,2),BD2(:,1),BD2(:,2));

%交集
Area1=and(IsInPoly1,IsInPoly2);
Area2=and(IsInPoly1,~IsInPoly2);
Area3=and(~IsInPoly1,IsInPoly2);
Area4=and(~IsInPoly1,~IsInPoly2);

figure()
hold on
scatter(xy2(Area1,1),xy2(Area1,2),24,1*ones(sum(Area1),1),'Marker','.')
scatter(xy2(Area2,1),xy2(Area2,2),24,2*ones(sum(Area2),1),'Marker','.')
scatter(xy2(Area3,1),xy2(Area3,2),24,3*ones(sum(Area3),1),'Marker','.')
scatter(xy2(Area4,1),xy2(Area4,2),24,4*ones(sum(Area4),1),'Marker','.')
colormap(lines(4))

Guess you like

Origin blog.csdn.net/weixin_42943114/article/details/124645273
Recommended