计算线段包围一点形成的包围角度

本文介绍了如何计算山脉对降水影响的量化方法,特别是山脉所围成的包围角和阻挡方位。算法通过计算一系列线段与点形成的角度并累加,找出极大值和极小值来确定包围角度。Python代码实现详细展示了这一过程,适用于复杂地形的分析。
摘要由CSDN通过智能技术生成


前言

通常山脉对降雨的影响比较大,比如秦岭山脉阻挡了北上的水汽,使南北方呈现出差异较大的降水水平。除此之外,其他小的山脉也会对降水有一定的影响,因此,研究降水的影响因子时,山脉是个不可忽略的因素。求山脉所围成的包围角和阻挡方位是量化山脉影响的方法之一,其中,山脉可以用线表示(如等高线),气象站点用点表示。这里提供一种计算山脉所围成包围角度和阻挡方位的算法


一、算法原理

对上述实例进行数学化描述:计算线段包围一点形成的包围角度和该线段对该点的阻挡方位。

通常较为简单的一种场景是:

上述线条AB对点O形成的包围角为AOB,只要指导线条起点和终点可以很容易求出角度。

由于显示场景较为复杂,存在多种多样的情形,通过起点和终点方式则不能轻易计算得到,如下面一些情形。


算法完备性:寻找共同规律。

线是由一串点相连构成的,具体为一条线由n个点构成(a, b, c, d, …),由n-1条小线段构成(ab, bc, cd, …)。

我们定义每条小线段与o构成的夹角,即aob,boc,cod,…,可以通过点乘计算;进一步定义角度的正负,叉乘向里为负,向外为正。并对所有小线段角度累加,以下是不同案例的统计情况:

可以发现,对角度累积求和,极大值和极小值所在点即是A和B;包围角度为极大值减去极小值。

二、代码实现(python)

NORTH_VEC = (0, 100) # 定义正北向量
EAST_VEC = (100, 0)  # 定义正东向量

def distance(x1, y1, x2, y2):   # (x1, y1),(x2, y2) 两点距离
    return math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))

def vector(point1, point2):   #  两点形成的向量
    return (point2[0] - point1[0], point2[1] - point1[1])

def angle(vec1, vec2):  #  向量夹角--带方向
    vec1dotvec2 = vec1[0] * vec2[0] + vec1[1] * vec2[1]
    absVec1 = math.sqrt(vec1[0] * vec1[0] + vec1[1] * vec1[1])
    absVec2 = math.sqrt(vec2[0] * vec2[0] + vec2[1] * vec2[1])
    ang = math.acos(vec1dotvec2 / (absVec1 * absVec2))
    if vec1[0] * vec2[1] - vec1[1] * vec2[0] < 0:
        ang = -ang
    return ang

def myMethod(point, line):
	"""
	point:点
	line:线
	"""
    middlePoint = line[int(len(line)/2)]
    endPoint = line[len(line) - 1]

    vecEndPoint = vector(point, endPoint)
    
    sumAngleList = []
    sumAngle = 0
    DirecList = []
    sumAngleList.append(sumAngle)
    for i in range(len(line) - 1):
        point1 = line[i]
        point2 = line[i + 1]
        vec1 = vector(point, point1)
        vec2 = vector(point, point2)
        ang = angle(vec1, vec2)

        Direc = math.fabs(angle(vec1, NORTH_VEC))   #  与正北方向形成的夹角,有两种情况,在2/3象限或在1/4象限。如果在2/3象限需要再运算:2*pi-夹角
        if math.fabs(angle(vec1, EAST_VEC)) > math.pi / 2:  #  如果同时与正东方向夹角大于pi/2,可以确定在2/3象限
            Direc = 2 * math.pi - Direc
        DirecList.append(Direc)

        sumAngle += ang
        sumAngleList.append(sumAngle)

    Direc = math.fabs(angle(vecEndPoint, NORTH_VEC))
    if math.fabs(angle(vecEndPoint, EAST_VEC)) > math.pi / 2:
        Direc = 2 * math.pi - Direc
    DirecList.append(Direc)

    sumAngleMax = -7
    sumAngleMin = 7
    startDirec = 0
    endDirec = 0
    for k in range(len(sumAngleList)):  #  找累加最大值和最小值,最大值-最小值为包围角度,对应的方向为起始包围方向和终止包围方向。
        if sumAngleList[k] > sumAngleMax:
            startDirec = DirecList[k]
            sumAngleMax = sumAngleList[k]
        if sumAngleList[k] < sumAngleMin:
            endDirec = DirecList[k]
            sumAngleMin = sumAngleList[k]
    bwAngle = sumAngleMax-sumAngleMin
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cshgiser

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

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

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

打赏作者

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

抵扣说明:

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

余额充值