Python 按一定顺序组合相邻的三维多边形

Python 按一定顺序组合相邻的三维多边形,python,geolocation,polygon,Python,Geolocation,Polygon,给定两个三维多边形,其缠绕顺序均为逆时针或顺时针: poly1 = np.array([[120787.075999871, 491779.675000143, -2.0699999332428], [120784.319999829, 491781.831000042, 5.96999979019165], [120784.319999829, 491781.831000042, -2.0699999332428], [120787.075999871, 491779.675000143, -

给定两个三维多边形,其缠绕顺序均为逆时针或顺时针:

poly1 = np.array([[120787.075999871, 491779.675000143, -2.0699999332428], [120784.319999829, 491781.831000042, 5.96999979019165], [120784.319999829, 491781.831000042, -2.0699999332428], [120787.075999871, 491779.675000143, -2.0699999332428]])
poly2 = np.array([[120787.075999871, 491779.675000143, -2.03999996185303], [120787.075999871, 491779.675000143, 5.90999984741211], [120784.319999829, 491781.831000042, 5.96999979019165], [120787.075999871, 491779.675000143, -2.03999996185303]])
如何在Python中将这些相邻多边形合并为一个多边形,同时保持顺序

以下是绘制两个相邻多边形的代码:

import matplotlib.pyplot as plt, numpy as np
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(poly1[:,0],poly1[:,1],poly1[:,2])
ax.plot(poly2[:,0],poly2[:,1],poly2[:,2])
ax.view_init(45, 45) 
plt.show()

我刚刚做了一个简单的解决方案,它允许组合两个多边形,至少有一个公共点和可能创建的连续线。 现在,没有公差,公共点必须是相同的,但在以后的日子里,我会把它作为函数的参数添加,因为我完全喜欢它。我将添加一些合并多边形的可能性,但我需要时间。也许,我会把它推到GitHub上,然后将链接粘贴到这里

poly2第一个和最后一个元素中的修改多边形与poly1中的修改多边形相同:

poly1=np.数组[[120787.075999871,491779.675000143,-2.069999332428],[120784.31999829,491781.831000042,5.9699979019165],[120784.319999829491781.831000042,-2.0699932428],[120787.075999871,491779.675000143,-.0699932428]] poly2=np.数组[[120787.075999871,491779.675000143,-2.0699999332428],[120787.075999871,491779.675000143,5.90999984741211],[120784.319999829,491781.831000042,5.969979019165],[120787.075999871,491779.675000143,--2.06999332428]] 这是一种平庸的解决方案,由于这种情况,代码并不漂亮,但它可以工作:

def merge_polygonsp1、p2: 简单的函数,允许将两个多边形组合为至少有一个公共点的numpy阵列 和潜在的创造连续线。 :return:多边形合并p1和p2为numpy数组 poly1_l=listp1[1:] poly2_l=listp2[1:] 公共_i1=[] 公共_i2=[] 寻找共同点 对于i,j in i,j for i in RangePoly1_l对于j in RangePoly2_l: 如果np.allpoly1_l[i]==poly2_l[j]: 普通附录 公共_i2.j 如果不常见,请参见第1部分: 升起例外无法合并多边形-没有公共点! 合并具有1个公共点的多边形 如果lencommon_i1==1: poly1_l[common_i1[0]:common_i1[0]=poly2_l[common_i2[0]:]+poly2_l[:common_i2[0]][::-1] poly1_l.附录poly1_l[0] 返回np.arraypoly1\u l 其他:合并具有2+公共点的多边形 开始=[无,无] 结束=[无,无] 检查公共点是否正在创建连续线 对于迭代器,枚举中的common_l common_i1,common_i2: 对于我的共同点: 如果不是i-1%公共透镜1,而不是i+1%公共透镜1: 升起例外不能合并多边形-公共部分必须是连续的! elif not i-1%lenpoly1_l公共部分:标记公共部分的开始和结束 开始[迭代器]=i elif not i+1%的普通透镜: 结束[迭代器]=i 由于公共零件的位置而合并多边形 如果isinstancestart[0],int和isinstanceend[0],int: poly3_l=[] 如果开始[0]<结束[0]:如果第一个多边形中的公共部分未被列表的开始和结束中断 如果开始[1]<结束[1]:如果第二个多边形中的公共部分未被列表的开始和结束中断 poly3_l.extendpoly1_l[:开始[0]] if np.allpoly1_l[start[0]]==poly2_l[start[1]]:如果第一个多边形中链的起点对应于第二个多边形中链的起点 poly3_l.extendpoly2_l[:开始[1]+1][:-1] poly3_l.extendpoly2_l[end[1]:][::-1] 其他: poly3_l.extendpoly2_l[end[1]:] poly3_l.extendpoly2_l[:开始[1]+1] poly3_l.extendpoly1_l[end[0]+1:] poly3_l.附录poly3_l[0] 其他: poly3_l.extendpoly1_l[:开始[0]] 如果np.allpoly1\u l[start[0]==poly2\u l[start[1]]: poly3_l.extendpoly2_l[end[1]:start[1]+1][:-1] 其他: poly3_l.extendpoly2_l[end[1]:start[1]+1] poly3_l.extendpoly1_l[end[0]+1:] poly3_l.附录poly3_l[0] 其他: 如果开始[1]<结束[1]: poly3_l.extendpoly2_l[:开始[1]+1] 如果np.allpoly1\u l[start[0]==poly2\u l[start[1]]: poly3_l.extendedpoly1_l[end[0]+1:start[0][::-1] 其他: poly3_l.extendpoly1_l[end[0]+1:start[0]] poly3_l.extendpoly2_l[end[1]:] poly3_l.附录poly3_l[0] 其他: poly3_l.extendpoly1_l[end[0]+1:start[0]] 如果np.allpoly1\u l[start[0]==poly2\u l[start[1]]: poly3_l.extendpoly2_l[end[1]:start[1]+1][:-1] 其他: poly3_l.extendpoly2_l[end[1]:start[1]+1] poly3_l.附录poly3_l[0] 返回np.arraypoly3\u l 其他: 升起例外多边形是相同的-不需要合并它们。 这个函数用两个tringle测试了所有的可能性,但我会做更多的测试

它看起来是怎样的:

如果要将多边形边缘化为一个形状,只需使用列表:

poly3=np.arraylistpoly1+listpoly2 您的案例看起来是什么样的:


我希望它能帮助你

我刚刚提出了一个简单的解决方案,它允许将两个多边形与至少一个公共点和可能创建的连续线相结合。 现在,没有公差,公共点必须是相同的,但在以后的日子里,我会把它作为函数的参数添加,因为我完全喜欢它。我将添加一些合并多边形的可能性,但我需要时间。也许,我会把它推到GitHub上,然后将链接粘贴到这里

poly2第一个和最后一个元素中的修改多边形与poly1中的修改多边形相同:

poly1=np.数组[[120787.075999871,491779.675000143,-2.069999332428],[120784.31999829,491781.831000042,5.9699979019165],[120784.319999829491781.831000042,-2.0699932428],[120787.075999871,491779.675000143,-.0699932428]] poly2=np.数组[[120787.075999871,491779.675000143,-2.0699999332428],[120787.075999871,491779.675000143,5.90999984741211],[120784.319999829,491781.831000042,5.969979019165],[120787.075999871,491779.675000143,--2.06999332428]] 这是一种平庸的解决方案,由于这种情况,代码并不漂亮,但它可以工作:

def merge_polygonsp1、p2: 简单的函数,允许将两个多边形组合为至少有一个公共点的numpy阵列 和潜在的创造连续线。 :return:多边形合并p1和p2为numpy数组 poly1_l=listp1[1:] poly2_l=listp2[1:] 公共_i1=[] 公共_i2=[] 寻找共同点 对于i,j in i,j for i in RangePoly1_l对于j in RangePoly2_l: 如果np.allpoly1_l[i]==poly2_l[j]: 普通附录 公共_i2.j 如果不常见,请参见第1部分: 升起例外无法合并多边形-没有公共点! 合并具有1个公共点的多边形 如果lencommon_i1==1: poly1_l[common_i1[0]:common_i1[0]=poly2_l[common_i2[0]:]+poly2_l[:common_i2[0]][::-1] poly1_l.附录poly1_l[0] 返回np.arraypoly1\u l 其他:合并具有2+公共点的多边形 开始=[无,无] 结束=[无,无] 检查公共点是否正在创建连续线 对于迭代器,枚举中的common_l common_i1,common_i2: 对于我的共同点: 如果不是i-1%公共透镜1,而不是i+1%公共透镜1: 升起例外不能合并多边形-公共部分必须是连续的! elif not i-1%lenpoly1_l公共部分:标记公共部分的开始和结束 开始[迭代器]=i elif not i+1%的普通透镜: 结束[迭代器]=i 由于公共零件的位置而合并多边形 如果isinstancestart[0],int和isinstanceend[0],int: poly3_l=[] 如果开始[0]<结束[0]:如果第一个多边形中的公共部分未被列表的开始和结束中断 如果开始[1]<结束[1]:如果第二个多边形中的公共部分未被列表的开始和结束中断 poly3_l.extendpoly1_l[:开始[0]] if np.allpoly1_l[start[0]]==poly2_l[start[1]]:如果第一个多边形中链的起点对应于第二个多边形中链的起点 poly3_l.extendpoly2_l[:开始[1]+1][:-1] poly3_l.extendpoly2_l[end[1]:][::-1] 其他: poly3_l.extendpoly2_l[end[1]:] poly3_l.extendpoly2_l[:开始[1]+1] poly3_l.extendpoly1_l[end[0]+1:] poly3_l.附录poly3_l[0] 其他: poly3_l.extendpoly1_l[:开始[0]] 如果np.allpoly1\u l[start[0]==poly2\u l[start[1]]: poly3_l.extendpoly2_l[end[1]:start[1]+1][:-1] 其他: poly3_l.extendpoly2_l[end[1]:start[1]+1] poly3_l.extendpoly1_l[end[0]+1:] poly3_l.附录poly3_l[0] 其他: 如果开始[1]<结束[1]: poly3_l.extendpoly2_l[:开始[1]+1] 如果np.allpoly1\u l[start[0]==poly2\u l[start[1]]: poly3_l.extendedpoly1_l[end[0]+1:start[0][::-1] 其他: poly3_l.extendpoly1_l[end[0]+1:start[0]] poly3_l.extendpoly2_l[end[1]:] poly3_l.附录poly3_l[0] 其他: poly3_l.extendpoly1_l[end[0]+1:start[0]] 如果np.allpoly1\u l[start[0]==poly2\u l[start[1]]: poly3_l.extendpoly2_l[end[1]:start[1]+1][:-1] 其他: poly3_l.extendpoly2_l[end[1]:start[1]+1] poly3_l.附录poly3_l[0] 返回np.arraypoly3\u l 其他: 升起例外多边形是相同的-不需要合并它们。 这个函数用两个tringle测试了所有的可能性,但我会做更多的测试

它看起来是怎样的:

如果要将多边形边缘化为一个形状,只需使用列表:

poly3=np.arraylistpoly1+listpoly2 您的案例看起来是什么样的:


我希望它能帮助你

尽管poly1和poly2中的点看起来像绘图上的同一点,但它们的坐标并不完全匹配。 我猜您希望算法使用足够接近的值,即如果点之间的距离小于给定公差,例如0.1,则它们被视为同一点

通过查找公共边并将其删除,可以连接两个多边形

为了找到公共边,我们首先确定两个多边形的哪些点是公共的。我看了一下,选择了cKDTree方法。 它的工作原理是

为一个多边形的每个点查找另一个多边形中最近的相邻点 比较这两点之间的距离。如果距离小于我们设定的公差,我们认为它们是相同的点,对两个多边形都是相同的。 一旦确定了哪些点是公共点,就可以验证它们是否相邻。如果是,则已找到要删除的边

生成的多边形将由以下部分组成:

poly1的所有点 poly2中不形成公共边的点 代码如下:

import matplotlib.pyplot as plt, numpy as np
from mpl_toolkits.mplot3d import Axes3D
from scipy.spatial import cKDTree

poly1 = np.array([[120787.075999871, 491779.675000143, -2.0699999332428], [120784.319999829, 491781.831000042, 5.96999979019165], [120784.319999829, 491781.831000042, -2.0699999332428], [120787.075999871, 491779.675000143, -2.0699999332428]])
poly2 = np.array([[120787.075999871, 491779.675000143, -2.03999996185303], [120787.075999871, 491779.675000143, 5.90999984741211], [120784.319999829, 491781.831000042, 5.96999979019165], [120787.075999871, 491779.675000143, -2.03999996185303]])


def is_close(a, b, tolerance):
    # Get closest distances for each pt in a
    dist = cKDTree(b).query(a, k=1)[0] # k=1 selects closest one neighbor

    # Check the distances against the given tolerance value
    return dist <= tolerance

def find_consecutive_true_values(arr):
    i = 0
    while i < len(arr) - 1:
        if arr[i] and arr[i+1]:
            return i
        i+=1
    raise Exception('No common edge found')

# Find points in poly1, which are closer than given tolerance to any point in poly2
# and vice versa
tolerance = 0.1
points_in_poly1_close_to_poly2 = is_close(poly1, poly2, tolerance)
points_in_poly2_close_to_poly1 = is_close(poly2, poly1, tolerance)

# Scan each array for two adjacent true values (points at those two indices 
# form an edge which is common to both polygons and which we want to remove).
# Idx1 (resp. idx2) will contain the index of the first point of that common edge in poly1 (resp. poly2)
idx1 = find_consecutive_true_values(points_in_poly1_close_to_poly2)
idx2 = find_consecutive_true_values(points_in_poly2_close_to_poly1)

#Split poly1 into two parts:
#  first part contains points from the start up to the first point of the common edge (inclusive)
#  second part contains points from the second point of the common edge to the end
poly1_part1 = poly1[:idx1+1]
poly1_part2 = poly1[idx1+1:]

#Remove common edge from poly2, depending on where it is located, we end up with one or two parts
if idx2 == len(poly2) - 2:
    poly2_part1 = poly2[1:len(poly2) - 2]
    poly2_part2 = None
elif idx2 == 0:
    poly2_part1 = poly2[2:len(poly2) - 1]
    poly2_part2 = None
else:
    poly2_part1 = poly2[idx2+2:]
    poly2_part2 = poly2[1:idx2]

#Create the resulting polygon by concatenating the individual parts (poly2_part2 may be empty)
if(poly2_part2 is None):
    poly = np.concatenate((poly1_part1, poly2_part1, poly1_part2))
else:
    poly = np.concatenate((poly1_part1, poly2_part1, poly2_part2, poly1_part2))


fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(poly[:,0], poly[:,1], poly[:,2])


ax.view_init(45, 45) 
plt.show()
代码远非惯用语言,如果您了解Python,请随意编辑:


poly1和poly2中的点的坐标并不完全匹配,尽管它们看起来像绘图上的同一点。 我猜您希望算法使用足够接近的值,即如果点之间的距离小于给定公差,例如0.1,则它们被视为同一点

通过查找公共边并将其删除,可以连接两个多边形

为了找到公共边,我们首先确定两个多边形的哪些点是公共的。我看了一下,选择了cKDTree方法。 它的工作原理是

为一个多边形的每个点查找另一个多边形中最近的相邻点 比较这两点之间的距离。如果距离小于我们设定的公差,我们认为它们是相同的点,对两个多边形都是相同的。 一旦确定了哪些点是公共点,就可以验证它们是否相邻。如果是,则已找到要删除的边

生成的多边形将由以下部分组成:

poly1的所有点 poly2中不形成公共边的点 代码如下:

import matplotlib.pyplot as plt, numpy as np
from mpl_toolkits.mplot3d import Axes3D
from scipy.spatial import cKDTree

poly1 = np.array([[120787.075999871, 491779.675000143, -2.0699999332428], [120784.319999829, 491781.831000042, 5.96999979019165], [120784.319999829, 491781.831000042, -2.0699999332428], [120787.075999871, 491779.675000143, -2.0699999332428]])
poly2 = np.array([[120787.075999871, 491779.675000143, -2.03999996185303], [120787.075999871, 491779.675000143, 5.90999984741211], [120784.319999829, 491781.831000042, 5.96999979019165], [120787.075999871, 491779.675000143, -2.03999996185303]])


def is_close(a, b, tolerance):
    # Get closest distances for each pt in a
    dist = cKDTree(b).query(a, k=1)[0] # k=1 selects closest one neighbor

    # Check the distances against the given tolerance value
    return dist <= tolerance

def find_consecutive_true_values(arr):
    i = 0
    while i < len(arr) - 1:
        if arr[i] and arr[i+1]:
            return i
        i+=1
    raise Exception('No common edge found')

# Find points in poly1, which are closer than given tolerance to any point in poly2
# and vice versa
tolerance = 0.1
points_in_poly1_close_to_poly2 = is_close(poly1, poly2, tolerance)
points_in_poly2_close_to_poly1 = is_close(poly2, poly1, tolerance)

# Scan each array for two adjacent true values (points at those two indices 
# form an edge which is common to both polygons and which we want to remove).
# Idx1 (resp. idx2) will contain the index of the first point of that common edge in poly1 (resp. poly2)
idx1 = find_consecutive_true_values(points_in_poly1_close_to_poly2)
idx2 = find_consecutive_true_values(points_in_poly2_close_to_poly1)

#Split poly1 into two parts:
#  first part contains points from the start up to the first point of the common edge (inclusive)
#  second part contains points from the second point of the common edge to the end
poly1_part1 = poly1[:idx1+1]
poly1_part2 = poly1[idx1+1:]

#Remove common edge from poly2, depending on where it is located, we end up with one or two parts
if idx2 == len(poly2) - 2:
    poly2_part1 = poly2[1:len(poly2) - 2]
    poly2_part2 = None
elif idx2 == 0:
    poly2_part1 = poly2[2:len(poly2) - 1]
    poly2_part2 = None
else:
    poly2_part1 = poly2[idx2+2:]
    poly2_part2 = poly2[1:idx2]

#Create the resulting polygon by concatenating the individual parts (poly2_part2 may be empty)
if(poly2_part2 is None):
    poly = np.concatenate((poly1_part1, poly2_part1, poly1_part2))
else:
    poly = np.concatenate((poly1_part1, poly2_part1, poly2_part2, poly1_part2))


fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(poly[:,0], poly[:,1], poly[:,2])


ax.view_init(45, 45) 
plt.show()
代码远非惯用语言,如果您了解Python,请随意编辑:


两个阵列中的第一个点和最后一个点是否应该完全相同以对多边形进行边缘处理?两个阵列中的第一个点和最后一个点是否应该完全相同以对多边形进行边缘处理?感谢您详细解释问题和代码。这真的很有帮助,解决了我的编程问题!嗨,这两个多边形上的代码不起作用。你知道为什么吗?[121364.656,485837.156,485837.156,1.344],[121364.656.656,485837.156,1.342,”121364.656,485837.156,1.342],[121364.656.656,485837.156,485837.156,1.344],[121364.656.656.656,48586,4858583737373737.156,485837.156,1.156,1.156,1.341.1.1.342],[121364[[121364.654.654.654.656.656.656 6.656.656,48587.656.656,485837.156,485837.156,485837.156,485837.156,1.156,1.156,1.156,1.156,1.156,前两个顶点表示小公差范围内的同一点:[121364.688,485837.156,1.344]vs[121364.656,485837.156,1.342]感谢您详细解释问题和代码。这真的很有帮助,解决了我的编程问题!嗨,这两个多边形上的代码不起作用。你知道为什么吗?[121364.656,485837.156,485837.156,1.344],[121364.656.656,485837.156,1.342,”121364.656,485837.156,1.342],[121364.656.656,485837.156,485837.156,1.344],[121364.656.656.656,48586,4858583737373737.156,485837.156,1.156,1.156,1.341.1.1.342],[121364[[121364.654.654.654.656.656.656 6.656.656,48587.656.656,485837.156,485837.156,485837.156,485837.156,1.156,1.156,1.156,1.156,1.156,前两个顶点表示小公差范围内的同一点:[121364.688,485837.156,1.344]vs[121364.656,485837.156,1.342]