线段和四边形的交点计算

线段和四边形的交点计算,可以转化为线段和四边形的四条边各自进行交点计算,而线段和线段交点计算的原理已经在之前的一篇博客中介绍过了,这里不再赘述。
为了加快速度,在计算和四条边的交点之前,我们先进行一个快速排斥实验,即判断线段的最小包围盒是否和四边形的最小包围盒相交,若不相交,则无需再进行交点的计算,可节省下相等一部分的计算量。
以下是python代码实现:

import geopandas
from shapely import geometry
import operator
import matplotlib.pyplot as plt

def findIntersection(x1, y1, x2, y2, x3, y3, x4, y4):        #求直线交点
    t=((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4))
    if t!=0:                 #有交点
        px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / t
        py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / t
        return [px,py]
    else:
        return None

def findLineIntersection(p1,p2,p3,p4):         #求线段p1p2和线段p3p3的交点
    x1,y1=p1
    x2,y2=p2
    x3,y3=p3
    x4,y4=p4
    #
    t = ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
    if t != 0:  # 有交点
        px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / t
        py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / t
        if px>=min(x1,x2) and px<=max(x1,x2) and px>=min(x3,x4) and px<=max(x3,x4):      #交点在线段上
            return [px, py]
        else:
            return None
    else:
        return None

def isIntersect(line,parallelogram):
    l1,l2=line
    p1,p2,p3,p4=parallelogram
    x1,x2=min(l1[0],l2[0]),max(l1[0],l2[0])
    y1,y2=min(l1[1],l2[1]),max(l1[1],l2[1])                           #线段的最小包围盒
    x3,x4=min(p1[0],p2[0],p3[0],p4[0]),max(p1[0],p2[0],p3[0],p4[0])
    y3,y4=min(p1[1],p2[1],p3[1],p4[1]),max(p1[1],p2[1],p3[1],p4[1])   #四边形的最小包围盒
    #
    if x1<=x4 and x3<=x2 and y1<=y4 and y3<=y2:
        return True
    else:
        return False


def findParallelogramIntersection(line,parallelogram):          #求线段和平行四边形的交点
    if not isIntersect(line,parallelogram):
        #未通过快速排斥实验,一定不相交
        print("未通过快速排斥实验")
        return []
    l1,l2=line
    p1,p2,p3,p4=parallelogram
    cp1=findLineIntersection(l1,l2,p1,p2)
    cp2=findLineIntersection(l1,l2,p2,p3)
    cp3=findLineIntersection(l1,l2,p3,p4)
    cp4=findLineIntersection(l1,l2,p4,p1)
    old_cps=[]
    if cp1:
        old_cps.append(cp1)
    if cp2:
        old_cps.append(cp2)
    if cp3:
        old_cps.append(cp3)
    if cp4:
        old_cps.append(cp4)
    #print(old_cps)
    cps=[]
    for cp in old_cps:
        if cp not in cps:
            cps.append(cp)
    #print(cps)
    return cps

if __name__=="__main__":
    line=[(-1,-1),(9,-5)]
    parallelogram=[(0,1),(2,1),(4,3),(2,3)]
    ax=geopandas.GeoSeries(geometry.LineString(line)).plot(color='r')
    geopandas.GeoSeries(geometry.Polygon(parallelogram)).plot(ax=ax)
    points=findParallelogramIntersection(line,parallelogram)
    print(points)
    assert len(points)<=2
    if len(points)==2:
        geopandas.GeoSeries([geometry.Point(points[0]),geometry.Point(points[1])]).plot(ax=ax,color='r')
    plt.show()

结果

1.未通过快速排斥实验的情况
在这里插入图片描述

2.通过快速排斥实验但没交点
在这里插入图片描述
3.有一个交点
在这里插入图片描述
4.两个交点
在这里插入图片描述

改进

之前的代码,由于计算机在表示数据时存在误差,因此有时会发生错误(当四边形的某条边垂直或平行于X轴时),现加入了一个误差容忍因子eps,解决了这个问题。代码如下

import geopandas
from shapely import geometry
import operator
import matplotlib.pyplot as plt

def findIntersection(x1, y1, x2, y2, x3, y3, x4, y4):        #求直线交点
    t=((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4))
    if t!=0:                 #有交点
        px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / t
        py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / t
        return [px,py]
    else:
        return None

def findLineIntersection(p1,p2,p3,p4):         #求线段p1p2和线段p3p3的交点
    eps=1e-6
    x1,y1=p1
    x2,y2=p2
    x3,y3=p3
    x4,y4=p4
    #
    t = ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
    if t != 0:  # 有交点
        px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / t
        py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / t
        if px>=min(x1,x2)-eps and px<=max(x1,x2)+eps and px>=min(x3,x4)-eps and px<=max(x3,x4)+eps and \
           py>=min(y1,y2)-eps and py<=max(y1,y2)+eps and py>=min(y3,y4)-eps and py<=max(y3,y4)+eps:      #交点在线段上
            return [px, py]
        else:
            return None
    else:
        return None

def isIntersect(line,parallelogram):
    l1,l2=line
    p1,p2,p3,p4=parallelogram
    x1,x2=min(l1[0],l2[0]),max(l1[0],l2[0])
    y1,y2=min(l1[1],l2[1]),max(l1[1],l2[1])                           #线段的最小包围盒
    x3,x4=min(p1[0],p2[0],p3[0],p4[0]),max(p1[0],p2[0],p3[0],p4[0])
    y3,y4=min(p1[1],p2[1],p3[1],p4[1]),max(p1[1],p2[1],p3[1],p4[1])   #四边形的最小包围盒
    #
    if x1<=x4 and x3<=x2 and y1<=y4 and y3<=y2:
        return True
    else:
        return False


def findParallelogramIntersection(line,parallelogram):          #求线段和平行四边形的交点
    if not isIntersect(line,parallelogram):
        #未通过快速排斥实验,一定不相交
        #print("未通过快速排斥实验")
        return []
    l1,l2=line
    p1,p2,p3,p4=parallelogram
    cp1=findLineIntersection(l1,l2,p1,p2)
    cp2=findLineIntersection(l1,l2,p2,p3)
    cp3=findLineIntersection(l1,l2,p3,p4)
    cp4=findLineIntersection(l1,l2,p4,p1)
    old_cps=[]
    if cp1:
        old_cps.append(cp1)
    if cp2:
        old_cps.append(cp2)
    if cp3:
        old_cps.append(cp3)
    if cp4:
        old_cps.append(cp4)
    #print(old_cps)
    cps=[]
    for cp in old_cps:
        if cp not in cps:
            cps.append(cp)
    #print(cps)
    return cps

if __name__=="__main__":
    line=[(-1,-1),(6,5)]
    parallelogram=[(0,1),(2,1),(4,3),(2,3)]
    ax=geopandas.GeoSeries(geometry.LineString(line)).plot(color='r')
    geopandas.GeoSeries(geometry.Polygon(parallelogram)).plot(ax=ax)
    points=findParallelogramIntersection(line,parallelogram)
    print(points)
    assert len(points)<=2
    if len(points)==2:
        geopandas.GeoSeries([geometry.Point(points[0]),geometry.Point(points[1])]).plot(ax=ax,color='r')
    plt.show()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA硅农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值