Python 使用matplotlib求解多边形中的点

Python 使用matplotlib求解多边形中的点,python,algorithm,python-2.7,matplotlib,point-in-polygon,Python,Algorithm,Python 2.7,Matplotlib,Point In Polygon,我正在寻找一种算法来检查一个点是否在多边形内 我目前正在使用mplPath并包含_point(),但在某些情况下它似乎不起作用 2016年9月16日编辑: 好的,我通过简单地检查点是否也在边上来导入代码。不过,对于矩形和蝴蝶结示例,我仍然存在一些问题: 新代码: #for PIP problem import matplotlib.path as mplPath import numpy as np #for plot import matplotlib.pyplot as plt def

我正在寻找一种算法来检查一个点是否在多边形内

我目前正在使用mplPath并包含_point(),但在某些情况下它似乎不起作用

2016年9月16日编辑:

好的,我通过简单地检查点是否也在边上来导入代码。不过,对于矩形和蝴蝶结示例,我仍然存在一些问题:

新代码:

#for PIP problem
import matplotlib.path as mplPath
import numpy as np
#for plot
import matplotlib.pyplot as plt


def plot(poly,points):
    bbPath = mplPath.Path(poly)
    #plot polygon
    plt.plot(*zip(*poly))

    #plot points
    xs,ys,cs = [],[],[]
    for point in points:
        xs.append(point[0])
        ys.append(point[1])
        color = inPoly(poly,point)
        cs.append(color)
        print point,":", color
    plt.scatter(xs,ys, c = cs , s = 20*4*2)

    #setting limits
    axes = plt.gca()
    axes.set_xlim([min(xs)-5,max(xs)+50])
    axes.set_ylim([min(ys)-5,max(ys)+10])

    plt.show()

def isBetween(a, b, c): #is c between a and b ?
    crossproduct = (c[1] - a[1]) * (b[0] - a[0]) - (c[0] - a[0]) * (b[1] - a[1])
    if abs(crossproduct) > 0.01 : return False   # (or != 0 if using integers)

    dotproduct = (c[0] - a[0]) * (b[0] - a[0]) + (c[1] - a[1])*(b[1] - a[1])
    if dotproduct < 0 : return False

    squaredlengthba = (b[0] - a[0])*(b[0] - a[0]) + (b[1] - a[1])*(b[1] - a[1])
    if dotproduct > squaredlengthba: return False

    return True

def get_edges(poly):
    # get edges
    edges = []
    for i in range(len(poly)-1):
        t = [poly[i],poly[i+1]]
        edges.append(t)
    return edges

def inPoly(poly,point):
    if bbPath.contains_point(point) == True:
        return 1
    else:
        for e in get_edges(poly):
            if isBetween(e[0],e[1],point):
                return 1
    return 0
# TESTS ========================================================================
#set up poly
polys = {
1 : [[10,10],[10,50],[50,50],[50,80],[100,80],[100,10],[10,10]], # test rectangulary shape
2 : [[20,10],[10,20],[30,20],[20,10]], # test triangle
3 : [[0,0],[0,10],[20,0],[20,10],[0,0]], # test bow-tie
4 : [[0,0],[0,10],[20,10],[20,0],[0,0]] # test rect
}

#points to check
points = {
1 : [(10,25),(50,75),(60,10),(20,20),(20,60),(40,50)], # rectangulary shape test pts
2 : [[20,10],[10,20],[30,20],[-5,0],[20,15]] , # triangle  test pts
3 : [[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,5]],  # bow-tie shape test pts
4 : [[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,5]]  # rect shape test pts
}

#print bbPath.contains_points(points) #0 if outside, 1 if inside
for data in zip(polys.itervalues(),points.itervalues()):
    plot(data[0],data[1])
我得出以下结论。正如您所看到的,红色包围的三个点表示为多边形外部(蓝色),而我希望它们位于多边形内部

我还尝试更改路径的半径值
bbPath.contains_points(points,radius=1.)
,但没有任何区别

欢迎任何帮助

编辑:


这个问题的答案中提出的算法的截图似乎表明它在其他情况下是失败的。

如果做得很长,你可能会偏离原则:如果交叉数是奇数,一个点在多边形内部,如果交叉数是偶数,同样在多边形外部。下面是我与上面给出的测试用例一起编写的一些草率的python

#多边形点:[[x,y],…]
点数=[[10,10]、[10,50]、[50,50]、[50,80]、[100,80]、[100,10]]
#获得优势
边=[]
对于范围内的i(长度(点)-1):
t=[点[i],点[i+1]]
边。追加(t)
#获取要用作光线长度的最小和最大x值
xmax=max(点,键=lambda项:项[1])[0]
xmin=min(点,键=lambda项:项[1])[1]
dist=xmaxxmin
#如果p1、p2、p3在同一行上,则返回True
def共线(p1、p2、p3):
返回值(p1[0]*(p2[1]-p3[1])+p2[0]*(p3[1]-p1[1])+p3[0]*(p1[1]-p2[1])==0
#如果p1位于线段p2-p3上,则返回True
范围内的def(p1、p2、p3):
dx=abs(p3[0]-p2[0])
dy=abs(p3[1]-p2[1])
如果abs(p3[0]-p1[0])+abs(p2[0]-p1[0])==dx和abs(p3[1]-p1[1])+abs(p2[1]-p1[1])==dy:
返回真值
返回错误
#直线段之间的交点
#(x1,y1)-(x1+dist,y1)和
#(x3,y3)-(x4,y4)
def相交(x1、y1、x3、y3、x4、y4):
x2=x1+dist
B1=x1-x2
C1=B1*y1
A2=y4-y3
B2=x3-x4
C2=A2*x3+B2*y3
det=-A2*B1
如果(det==0):
返回错误
x=(B2*C1-B1*C2)/det
如果在范围内((x,y1),(x3,y3),(x4,y4)):
返回真值
返回错误
#如果点(x,y)在内部,则返回True
#上面定义的多边形
定义isInside(x,y):
i=0
对于边中的边:
#如果(x,y)在边上,则返回True
如果共线((x,y),边[0],边[1])和inRange((x,y),边[0],边[1]):
返回真值
#如果边的两个x值都位于(x,y)的左侧
#如果边缘的两个y值都高于或低于(x,y)
#然后跳过
如果边[0][0]
好的,所以我最终还是用shapely完成了

#for PIP problem
import matplotlib.path as mplPath
import numpy as np
#for plot
import matplotlib.pyplot as plt
import shapely.geometry as shapely

class MyPoly(shapely.Polygon):
    def __init__(self,points):
        super(MyPoly,self).__init__(points)
        self.points = points
        self.points_shapely = [shapely.Point(p[0],p[1]) for p in points]

def convert_to_shapely_points_and_poly(poly,points):
    poly_shapely = MyPoly(poly)
    points_shapely = [shapely.Point(p[0],p[1]) for p in points]
    return poly_shapely,points_shapely

def plot(poly_init,points_init):
    #convert to shapely poly and points
    poly,points = convert_to_shapely_points_and_poly(poly_init,points_init)

    #plot polygon
    plt.plot(*zip(*poly.points))

    #plot points
    xs,ys,cs = [],[],[]
    for point in points:
        xs.append(point.x)
        ys.append(point.y)
        color = inPoly(poly,point)
        cs.append(color)
        print point,":", color
    plt.scatter(xs,ys, c = cs , s = 20*4*2)

    #setting limits
    axes = plt.gca()
    axes.set_xlim([min(xs)-5,max(xs)+50])
    axes.set_ylim([min(ys)-5,max(ys)+10])

    plt.show()


def isBetween(a, b, c): #is c between a and b ?
    crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y)
    if abs(crossproduct) > 0.01 : return False   # (or != 0 if using integers)

    dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y)*(b.y - a.y)
    if dotproduct < 0 : return False

    squaredlengthba = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)
    if dotproduct > squaredlengthba: return False

    return True

def get_edges(poly):
    # get edges
    edges = []
    for i in range(len(poly.points)-1):
        t = [poly.points_shapely[i],poly.points_shapely[i+1]]
        edges.append(t)
    return edges


def inPoly(poly,point):
    if poly.contains(point) == True:
        return 1
    else:
        for e in get_edges(poly):
            if isBetween(e[0],e[1],point):
                return 1
    return 0


# TESTS ========================================================================
#set up poly
polys = {
1 : [[10,10],[10,50],[50,50],[50,80],[100,80],[100,10],[10,10]], # test rectangulary shape
2 : [[20,10],[10,20],[30,20],[20,10]], # test triangle
3 : [[0,0],[0,10],[20,0],[20,10],[0,0]], # test bow-tie
4 : [[0,0],[0,10],[20,10],[20,0],[0,0]], # test rect clockwise
5 : [[0,0],[20,0],[20,10],[0,10],[0,0]] # test rect counter-clockwise
}

#points to check
points = {
1 : [(10,25),(50,75),(60,10),(20,20),(20,60),(40,50)], # rectangulary shape test pts
2 : [[20,10],[10,20],[30,20],[-5,0],[20,15]] , # triangle  test pts
3 : [[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,5]],  # bow-tie shape test pts
4 : [[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,2],[30,8]],  # rect shape test pts
5 : [[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,2],[30,8]]  # rect shape test pts
}

#print bbPath.contains_points(points) #0 if outside, 1 if inside
for data in zip(polys.itervalues(),points.itervalues()):
    plot(data[0],data[1])
PIP问题的
#
将matplotlib.path导入为mplPath
将numpy作为np导入
#阴谋
将matplotlib.pyplot作为plt导入
导入shapely.geometry作为shapely
类MyPoly(shapely.Polygon):
定义初始值(自身,点):
超级(MyPoly,self)。\uuuuu初始化\uuuuuuu(点)
self.points=点
self.points_shapely=[shapely.Point(p[0],p[1]),对于p in points]
def将_转换为_形状_点_和_多边形(多边形,点):
poly_shapely=MyPoly(poly)
点_shapely=[shapely.Point(p[0],p[1]),表示点中的p]
返回多边形形状,点形状
def绘图(多边形初始,点初始):
#转换为形状多边形和点
多边形,点=将_转换为_形状的_点和_多边形(poly_init,points_init)
#绘图多边形
plt.plot(*zip(*多边形点))
#绘图点
xs、ys、cs=[]、[]、[]
对于点到点:
追加(point.x)
附加(点y)
颜色=inPoly(多边形,点)
cs.append(彩色)
打印点“:”,颜色
plt.散射(xs,ys,c=cs,s=20*4*2)
#设定限制
轴=plt.gca()
轴设置_xlim([min(xs)-5,max(xs)+50])
轴设置Y轴([min(ys)-5,max(ys)+10])
plt.show()
定义在(a,b,c)之间:#c在a和b之间吗?
叉积=(c.y-a.y)*(b.x-a.x)-(c.x-a.x)*(b.y-a.y)
如果abs(叉积)>0.01:返回False#(如果使用整数,则返回!=0)
点积=(c.x-a.x)*(b.x-a.x)+(c.y-a.y)*(b.y-a.y)
如果dotproduct<0:返回False
平方长度ba=(b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y)
如果dotproduct>squaredlengthba:返回False
返回真值
def get_边(多边形):
#获得优势
边=[]
对于范围内的i(长度(多边形点)-1):
t=[poly.points\u shapely[i],poly.points\u shapely[i+1]]
边。追加(t)
返回边
def inPoly(多边形,点):
如果多边形包含(点)=真:
返回1
其他:
对于e-in-get_边(多边形):
如果介于(e[0],e[1],点之间:
返回1
返回0
#测验========================================================================
#设置多边形
多边形={
1:[10,10],[10,50],[50,50],[50,80],[100,80],[100,10],[10,10],#测试矩形形状
2:[20,10],[10,20],[30,20],[20,10],#测试三角形
3:[[0,0],[0,10],[20,0],[20,10],[0,0],#测试领结
4:[[0,0],[0,10],[20,10],[20,0],[0,0],#顺时针测试
5:[[0,0]、[20,0]、[20,10]、[0,10]、[0,0]]#逆时针测试
}
#检查要点
点数={
1:[(10,25),(50,75),(60,10),(20,20),(20,60),(40,50)],#矩形形状试验
2:[[20,10],[10,20],[30,20],-5,0],[20,15],#三角形测试点
3:[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,5],#领结形状试验
4 : [[0,0],
#for PIP problem
import matplotlib.path as mplPath
import numpy as np
#for plot
import matplotlib.pyplot as plt
import shapely.geometry as shapely

class MyPoly(shapely.Polygon):
    def __init__(self,points):
        super(MyPoly,self).__init__(points)
        self.points = points
        self.points_shapely = [shapely.Point(p[0],p[1]) for p in points]

def convert_to_shapely_points_and_poly(poly,points):
    poly_shapely = MyPoly(poly)
    points_shapely = [shapely.Point(p[0],p[1]) for p in points]
    return poly_shapely,points_shapely

def plot(poly_init,points_init):
    #convert to shapely poly and points
    poly,points = convert_to_shapely_points_and_poly(poly_init,points_init)

    #plot polygon
    plt.plot(*zip(*poly.points))

    #plot points
    xs,ys,cs = [],[],[]
    for point in points:
        xs.append(point.x)
        ys.append(point.y)
        color = inPoly(poly,point)
        cs.append(color)
        print point,":", color
    plt.scatter(xs,ys, c = cs , s = 20*4*2)

    #setting limits
    axes = plt.gca()
    axes.set_xlim([min(xs)-5,max(xs)+50])
    axes.set_ylim([min(ys)-5,max(ys)+10])

    plt.show()


def isBetween(a, b, c): #is c between a and b ?
    crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y)
    if abs(crossproduct) > 0.01 : return False   # (or != 0 if using integers)

    dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y)*(b.y - a.y)
    if dotproduct < 0 : return False

    squaredlengthba = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)
    if dotproduct > squaredlengthba: return False

    return True

def get_edges(poly):
    # get edges
    edges = []
    for i in range(len(poly.points)-1):
        t = [poly.points_shapely[i],poly.points_shapely[i+1]]
        edges.append(t)
    return edges


def inPoly(poly,point):
    if poly.contains(point) == True:
        return 1
    else:
        for e in get_edges(poly):
            if isBetween(e[0],e[1],point):
                return 1
    return 0


# TESTS ========================================================================
#set up poly
polys = {
1 : [[10,10],[10,50],[50,50],[50,80],[100,80],[100,10],[10,10]], # test rectangulary shape
2 : [[20,10],[10,20],[30,20],[20,10]], # test triangle
3 : [[0,0],[0,10],[20,0],[20,10],[0,0]], # test bow-tie
4 : [[0,0],[0,10],[20,10],[20,0],[0,0]], # test rect clockwise
5 : [[0,0],[20,0],[20,10],[0,10],[0,0]] # test rect counter-clockwise
}

#points to check
points = {
1 : [(10,25),(50,75),(60,10),(20,20),(20,60),(40,50)], # rectangulary shape test pts
2 : [[20,10],[10,20],[30,20],[-5,0],[20,15]] , # triangle  test pts
3 : [[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,5]],  # bow-tie shape test pts
4 : [[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,2],[30,8]],  # rect shape test pts
5 : [[0,0],[0,10],[20,0],[20,10],[10,0],[10,5],[15,2],[30,8]]  # rect shape test pts
}

#print bbPath.contains_points(points) #0 if outside, 1 if inside
for data in zip(polys.itervalues(),points.itervalues()):
    plot(data[0],data[1])