如何 select 根据点在 python 中的距离创建一些线

how to select some lines created by points based on their distances in python

我有一些通过连接规则网格的点创建的线,我想将正确的线配对以创建表面。这是我的点数组的坐标:

coord=np.array([[0.,0.,2.], [0.,1.,3.], [0.,2.,2.], [1.,0.,1.], [1.,1.,3.],\
                [1.,2.,1.], [2.,0.,1.], [2.,1.,1.], [3.,0.,1.], [4.,0.,1.]])

然后,我通过连接点来创建线。我的观点来自常规网格。所以,我有两组垂直的线。我称它们为蓝色(垂直)和红色(水平)线。为此:

blue_line=[]
for ind, i in enumerate (range (len(coord)-1)):
        if coord[i][0]==coord[i+1][0]:
            line=[ind, ind+1]
#             line=[x+1 for x in line]
            blue_line.append(line)
threshold_x = 1.5
threshold_y = 1.5
i, j = np.where((coord[:, 1] == coord[:, np.newaxis, 1]) &
    (abs(coord[:, 0] - coord[:, np.newaxis, 0]) < 1.2 * threshold_y))
# Restrict to where i is before j
i, j = i[i < j], j[i < j]
# Combine and print the indices
red_line=np.vstack([i, j]).T
blue_line=np.array(blue_line)
red_line=np.array(red_line)
all_line=np.concatenate((blue_line, red_line), axis=0)

为了找到创建曲面的正确线条,我检查了每条线与相邻线的中心。我从第一条蓝线开始,尝试是否还有其他三条相邻的线。如果我发现任何一条线的中心小于 threshold_x 并且它的 x 坐标与那条线不同,我将把它作为一对。然后我继续用这个规则搜索相邻的行。我的无花果清楚地表明了这一点。第一条蓝线通过箭头连接到编号为 3 的蓝线以及编号为 6 和 7 的红线。它不与编号为 2 的蓝线配对,因为它们具有相同的 x 坐标。我尝试了以下方法,但没有成功完成所有事情,我无法解决它:

ave_x=[]
ave_y=[]
ave_z=[]
for ind, line in enumerate (all_line):
    x = (coord[line][0][0]+coord[line][1][0])/2
    ave_x.append (x)
    y = (coord[line][0][1]+coord[line][1][1])/2
    ave_y.append (y)
    z = (coord[line][0][2]+coord[line][1][2])/2
    ave_z.append (z)
avs=np.concatenate((ave_x, ave_y, ave_z), axis=0)
avs=avs.reshape(-1,len (ave_x))
avs_f=avs.T
blue_red=[len (blue_line), len (red_line)]
avs_split=np.split(avs_f,np.cumsum(blue_red))[:-1] # first array is center of 
# blue lines and second is center of red lines
dists=[]
for data in avs_split:
    for ind, val in enumerate (data):
    if ind < len(data):
        for ind in range (len(data)-1):
            squared_dist = np.sum((data[ind]-data[ind+1])**2, axis=0)
            dists.append (squared_dist)

事实上,我希望我的代码给我结果列表,作为创建三个表面的线对:

[(1, 6, 3, 7), (2, 7, 4, 8), (3, 9, 5, 10)]

最后,我想找出在创建表面时未使用或已使用但比图中虚线的限制更近的线数。我有创建那条虚线的两点的坐标:

coord_dash=np.array([[2., 2., 2.], [5., 0., 1.]])

adjacency_threshold=2 这些行号也是:

[4, 10, 5, 11, 12]

提前感谢任何帮助。

我不确定我的答案是否符合您的要求,因为您的问题有点不清楚。首先,我将蓝线和红线创建为字典,其中键是行号,值是带有星号和端点号的元组。我还创建了一个字典 all_mid,其中键是行号,值是 pandas Series 和中点坐标。

import numpy as np
import pandas as pd

coord = np.array([[0.,0.,2.], [0.,1.,3.], [0.,2.,2.], [1.,0.,1.], [1.,1.,3.],
                  [1.,2.,1.], [2.,0.,1.], [2.,1.,1.], [3.,0.,1.], [4.,0.,1.]])

df = pd.DataFrame(
    data=sorted(coord, key=lambda item: (item[0], item[1], item[2])), 
    columns=['x', 'y', 'z'], 
    index=range(1, len(coord) + 1))

count = 1
blue_line = {}
for start, end in zip(df.index[:-1], df.index[1:]):
    if df.loc[start, 'x'] == df.loc[end, 'x']:
        blue_line[count] = (start, end)
        count += 1

red_line = []
index = df.sort_values('y').index
for start, end in zip(index[:-1], index[1:]):
    if df.loc[start, 'y'] == df.loc[end, 'y']:
        red_line.append((start, end))
red_line = {i + count: (start, end) 
            for i, (start, end) in enumerate(sorted(red_line))}


all_line = {**blue_line, **red_line}
all_mid = {i: (df.loc[start] + df.loc[end])/2 
           for i, (start, end) in all_line.items()}

线条看起来像这样:

In [875]: blue_line
Out[875]: {1: (1, 2), 2: (2, 3), 3: (4, 5), 4: (5, 6), 5: (7, 8)}

In [876]: red_line
Out[876]: 
{6: (1, 4),
 7: (2, 5),
 8: (3, 6),
 9: (4, 7),
 10: (5, 8),
 11: (7, 9),
 12: (9, 10)}

然后我定义一些实用函数:

  • adjacent returns True 如果输入点相邻。
  • left_to_right returns True 如果第一个点的x坐标小于第二个点的x坐标。
  • connections returns 一个字典,其中的键是一个行号,值是一个列表,其中的行号与之相连。
def adjacent(p, q, threshold=1):
    dx = abs(p['x'] - q['x'])
    dy = abs(p['y'] - q['y'])
    dxy = np.sqrt(dx**2 + dy**2)
    return np.max([dx, dy, dxy]) <= threshold


def left_to_right(p, q):
    return p['x'] < q['x']


def connections(midpoints, it):
    mapping = {}
    for start, end in it:
        if adjacent(midpoints[start], midpoints[end]):
            if left_to_right(midpoints[start], midpoints[end]):
                if start in mapping:
                    if end not in mapping[start]:
                        mapping[start].append(end)
                else:
                    mapping[start] = [end]
    return mapping

我们现在准备创建一个列表列表,其中每个子列表都有构成表面的行号:

from itertools import product, combinations

blues = blue_line.keys()
reds = red_line.keys()

blue_to_red = connections(all_mid, product(blues, reds))
blue_to_blue = connections(all_mid, combinations(blues, r=2))

surfaces = []
for start in blue_line:
    red_ends = blue_to_red.get(start, [])
    blue_ends = blue_to_blue.get(start, [])
    if len(red_ends) == 2 and len(blue_ends) == 1:
        surfaces.append(sorted([start] + red_ends + blue_ends))

这就是你得到的:

In [879]: surfaces
Out[879]: [[1, 3, 6, 7], [2, 4, 7, 8], [3, 5, 9, 10]]