如何根据点在python中的距离选择一些由点创建的线 [英] how to select some lines created by points based on their distances in python
问题描述
我有一些通过连接常规网格的点创建的线,并且希望将正确的线配对以创建表面.这是我的点数组的坐标:
I have some lines created by connecting points of a regular grid and want to pair the correct lines to create surfces. This is coordinates of my point array:
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.]])
然后,我通过连接点来创建线.我的观点来自常规网格.因此,我有两组垂直线.我称它们为蓝线(垂直)和红线(水平).为此:
Then, I created lines by connecting points. My points are from a regular grid. So, I have two perpendicular sets of lines. I called them blue (vertical) and red (horizontal) lines. To do so:
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
坐标.我尝试了以下方法,但不能完成所有事情,因此我无法解决:
To find the correct lines for creating surfaces, I check the center of each line with the adjacent ones. I start from the first blue line and try if there are other three adjacent lines or not. If I find any line which its center is less than threshold_x
and also its x
coordinate is different from that line, I will keep it as a pair. Then I continue searching for adjacent lines with this rule. My fig clearly shows it. First blue line is connected by an arrow to the blue line numbered 3 and also red lines numbered 6 and 7. It is not paired with blue line numbered 2 because they have the same x
coordinate. I tried the following but it was not successful to do all the things and I coulnot solve it:
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)
事实上,我希望我的代码能够将生成的列表作为成对的线对创建三个曲面:
In fact I expect my code to give me the resulting list as the pairs of the lines the create three surfaces:
[(1, 6, 3, 7), (2, 7, 4, 8), (3, 9, 5, 10)]
最后,我想找到在创建图面时未使用或已使用但比极限值更接近虚线的线数.我具有创建该虚线的两点的坐标:
At the end, I want to find the number of lines which are not used in creating the surfaces or are used but are closer than a limit the the dashed line in my fig. I have the coordinate of the two points creating that dashed line:
coord_dash=np.array([[2., 2., 2.], [5., 0., 1.]])
adjacency_threshold = 2这些行号也是:
adjacency_threshold=2 These line numbers are also:
[4, 10, 5, 11, 12]
预先感谢您的帮助.
推荐答案
我不确定我的答案是您要查找的内容,因为您的问题不清楚.首先,我将蓝线和红线创建为字典,其中键是线号,值是带有星号和终点号的元组.我还创建了一个字典 all_mid
,其中的键是行号,值是带有中点坐标的熊猫 Series
.
I'm not sure my answer is what you are looking for because your question is a bit unclear. To start off I create the blue and red lines as dictionaries, where the keys are the line numbers and the values are tuples with the star and end point numbers. I also create a dictionary all_mid
where the key is the line number and the value is a pandas Series
with the coordinates of the mid point.
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)}
然后我定义一些实用程序功能:
Then I define some utility functions:
- 如果输入点相邻,则
-
adjacent
返回True
. 如果第一个点的x坐标小于第二个点的x坐标,则 -
left_to_right
返回True
. -
connections
返回一个字典,其中的键是一个行号,值是一个连接了行号的列表.
adjacent
returnsTrue
if the input points are adjacent.left_to_right
returnsTrue
if the x coordinate of the first point is less than the x coordinate of the second point.connections
returns a dictionary in which the key is a line number and the value is a list with the line numbers connected to it.
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
我们现在准备创建一个列表列表,其中每个子列表都有构成曲面的行号:
We are now ready to create a list of lists, in which each sublist has the line numbers that make up a surface:
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]]
这篇关于如何根据点在python中的距离选择一些由点创建的线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!