как создавать линии и поверхности, используя точки регулярной сетки в Python

#python #algorithm #numpy

#питон #алгоритм #тупой

Вопрос:

У меня есть куча точек, и я хочу выполнить над ними некоторые геометрические процессы. Точки создают правильную сетку, включающую вертикальные (красные) и горизонтальные (синие) линии (загружается рисунок). Я хочу работать с числом, а также с координатами ( x,y,z ) точек. Например, номера точек и координаты в сценарии А на моем рисунке:

 point_no= np.arange (1,9)
point_A_coordinate=np.array([[0,0,2], [0,1,3], [0,2,2], [1,0,1], [1,1,3], [2,0,1], [2,1,1], [3,0,1]]
 

У меня есть количество точек в каждом столбце (я имею в виду красные линии) (показано красным кружком на рис.). В сценарии А это:

 chunk_val_A=np.array([3, 2, 2, 1])
 

Когда chunk_val_A[0] равно 3, это означает, что у меня есть 2 красные линии в этом фрагменте. Первая линия создается путем соединения точек 1 и 2, а вторая линия — через точки 2 и 3. Затем мой алгоритм должен знать, что точка номер 3 не должна быть соединена с 4, потому что chunk_val_A[0] равно 3. В следующем фрагменте я начинаю с соединения 4 с 5 и останавливаюсь на 5, потому chunk_val_A[0] chunk_val_A[1] что равно 5. В качестве выходных данных я хочу иметь номера точек, которые создают красную линию в виде пар:

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

Для синих линий (линий, соединяющих фрагменты) это немного сложнее. О количестве соединительных линий от блока i к блоку i 1 , если chunk_val массив убывает (сценарии A и C), он равен chunk_val_A[i 1] , если он возрастает (сценарии B и D), он равен chunk_val_A[i] . Но в сценарии E у меня есть как восходящий, так и нисходящий, и я хочу рассматривать правило до тех пор, пока оно не станет восходящим, а затем изменить его с того места, где оно начинает нисходить. У меня могут быть некоторые пики, но я хочу сохранить правило таким же, как и раньше. Чтобы выбрать, какие пары создают синие линии, если значения chunk_val[i] и chunk_val[i 1] совпадают, просто соедините первые строки каждого фрагмента, затем секунды и так далее (как в сценарии A я соединяю номера точек 4-6 и 8-7, чтобы соединить второй и третий фрагменты). В других случаях (например, в первом и втором фрагментах всех сценариев) я должен проверить координату. В сценарии A второй фрагмент имеет точку меньше, чем первый, и если я проверяю x и y точек point_A_coordinate[:,0:2] , пропущенная точка является последней точкой (это x и y должно быть 1 и 2) второго фрагмента. Таким образом, две соединительные линии будут начинаться с нижней части первого фрагмента. В сценарии B от первого до второго фрагмента первый пропускает нижнюю точку, поэтому единственная линия соединяется с верхней точкой второго фрагмента. Наконец, я хочу иметь такие пары для синих линий сценария А:

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

после создания таких линий я хочу использовать их для создания поверхностей. Если алгоритм сможет сначала изменить строку и пронумеровать их, а затем синие, я думаю, можно будет выяснить, где эти строки могут быть соединены. В сценарии А я показал номера строк в прямоугольнике. Я хочу иметь эти пары для создания поверхностей в сценарии A:

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

В качестве последнего вопроса я хочу извлечь количество строк, близких к пунктирной красной линии. В сценарии А они есть (я пометил их крестиком во всех сценариях).:

 [(2, 6, 8, 4, 9)]
 

Это то, что я хочу сделать в Python. Я очень признателен, если кто-нибудь поможет мне на любом этапе этого процесса. Я очень ценю любую помощь в решении такого длинного вопроса. Заранее благодарю.
Я попробовал следующий код для создания линий, но он не был успешным для всех случаев (я просто использовал функцию печати, чтобы показать пары):

 cord_A=np.array([[0,0,2], [0,1,3], [0,2,2], [1,0,1], [1,1,3], [2,0,1], [2,1,1], [3,0,1]])
cord_B=np.array([[0,2,2], [1,1,3], [1,2,2], [2,1,1], [2,2,3], [3,0,1], [3,1,1], [3,2,1]])
cord_C=np.array([[0,0,2], [0,1,3], [0,2,2], [1,1,1], [1,2,3], [2,1,1], [2,2,1], [3,2,1]])
cord_D=np.array([[0,0,2], [1,0,3], [1,1,2], [2,0,1], [2,1,3], [3,0,1], [3,1,1], [3,2,1]])

chunk_val_A=np.array([3, 2, 2, 1])
chunk_val_C=np.array([3, 2, 2, 1])
chunk_val_B=np.array([1, 2, 2, 3])
chunk_val_D=np.array([1, 2, 2, 3])

cord=np.array([[0,0,2], [0,1,3], [0,2,2], [1,0,1], [1,1,3], [2,0,1], [2,1,1], [3,0,1]]) # each time use one scenario
chunk_val=np.array([3, 2, 2, 1]) # again from the same scenario
summ=np.cumsum(chunk_val)
countinuous_point=np.arange(1,9)
splited_point=np.split(countinuous_point,np.cumsum(chunk_val))[:-1]
for i in countinuous_point:
    if i in summ:
        continue
    print (i, i 1) # it gives red lines
print ('All')
for j in range (len (chunk_val)-1):
    if chunk_val[j]==chunk_val[j 1]:
        for m, n in zip (splited_point[j], splited_point[j 1]):
            print (m, n) # it gives the blue lines when the chunks have the same length
    else:
        if cord[splited_point[j][-1]-1,1] > cord[splited_point[j 1][-1]-1,1]:
            for h, p in zip (splited_point[j], splited_point[j 1]):
                print (h,p) # it gives the blue lines when the chunks are like scenario A
        if cord[splited_point[j][-1],1] > cord[splited_point[j 1][0],1]:
            for h, p in zip (splited_point[j][1:], splited_point[j 1]):
                print (h,p) # it gives the blue lines when the chunks are like scenario B               
        if cord[splited_point[j][0],1] < cord[splited_point[j 1][0],1]:
            for h, p in zip (splited_point[j][1:], splited_point[j 1]):
                print (h,p) # it gives the blue lines when the chunks are like scenario C
        if cord[splited_point[j][-1],1] < cord[splited_point[j 1][-1],1]:
            for h, p in zip (splited_point[j][1:], splited_point[j 1]):
                print (h,p) # it gives the blue lines when the chunks are like scenario D
 

введите описание изображения здесь

Комментарии:

1. Не [(1, 5, 6, 6), (3, 7, 4, 8)] должно быть [(1, 5, 3, 6), (3, 7, 4, 8)] вместо этого?

2. Уважаемый @ wuerfelfreak, вы совершенно правы.

3. У меня есть несколько вопросов: вам нужно решение только для этих 5 конкретных случаев или для произвольных случаев? Вам также нужно знать, куда идут линии, или это нормально, если алгоритм напрямую выводит отмеченные поверхности? Откуда берутся пунктирные красные линии, есть ли правило, где они находятся?

4. Уважаемый @ wuerfelfreak, эти случаи показывают распределение моих точек. Количество точек меняется, но распределение будет одним из этих. Мне нужны только номера строк, например, какие номера строк создают первые поверхности и вторые и так далее. Как и в случае с пронумерованными строками, в сценарии A мне все равно, где находится строка, мне важен только ее номер. Пунктирные линии можно обнаружить по неровным поверхностям. Рассмотрим большую сетку, имеющую несколько поверхностей, затем разрежьте эту сетку по линиям, вы потеряете некоторые поверхности в прилегании к линии разреза. Заранее спасибо за вашу помощь.

Ответ №1:

Это даст мое решение для извлечения поверхностей. Я надеюсь, что это поможет вам. Однако не реализовал решение для нахождения краев, близких к красной пунктирной линии.

 import numpy as np

point_no= np.arange (1,9)
point_A_coordinate=np.array([[0,0,2], [0,1,3], [0,2,2], [1,0,1], [1,1,3], [2,0,1], [2,1,1], [3,0,1]])
chunk_val_A=np.array([3, 2, 2, 1])

max_x = max([x for x,y,z in point_A_coordinate])
max_y = max([y for x,y,z in point_A_coordinate])

points = np.full((max_x 1,max_y 1), -1) # Grid for storing points -1 marks that there is no point.
red_lines = []
blue_lines = []
n = 0
for chunk, chunk_val in enumerate(chunk_val_A):
    for i in range(chunk_val):
        points[chunk,i] = 1 # 1 markes that there is a point
        n  = 1
        if i > 0 and points[chunk,i-1] >= 0: red_lines.append( ((chunk,i-1), (chunk,i)) ) #adds red lines
        if chunk > 0 and points[chunk-1,i] >= 0: blue_lines.append(((chunk-1, i), (chunk,i))) # adds blue lines

print(points) # contains all your points like you would draw them on the paper. -1=no point . otherwise points z-kordinate
print(red_lines) # contains all red lines but named by there x,y cord-pairs
print(blue_lines) # contains all blue lines but named by there x,y cord-pairs

#surfaces
surfaces = []
for x in range(max_x):
    for y in range(max_y):
        if( points[x,y] >= 0 and # checks if all for points exist
            points[x 1,y] >= 0 and
            points[x,y 1] >= 0 and
            points[x 1,y 1] >= 0):
                surfaces.append((
                    red_lines.index( ((x,y), (x,y 1)) )  1, # gets the number of each line and adds it to the surface
                    blue_lines.index(((x, y), (x   1, y)))   len(red_lines)   1,
                    red_lines.index(((x   1, y), (x   1, y   1)))   1,
                    blue_lines.index( ((x, y 1), (x 1, y 1)))   len(red_lines)   1,
                ))

print(surfaces) # contains all surfaces

red_lines_numbers = [red_lines.index( red_line )  1 for red_line in red_lines] 
blue_lines_numbers = [blue_lines.index( blue_line )   len(red_lines)  1 for blue_line in blue_lines]

red_lines_points_numbers = [(
        [ i for i,cords in enumerate(point_A_coordinate) if all(cords[:2] == red_line[0])][0] 1,
        [ i for i,cords in enumerate(point_A_coordinate) if all(cords[:2] == red_line[1])][0] 1
    ) for red_line in red_lines]

blue_lines_points_numbers = [(
        [ i for i,cords in enumerate(point_A_coordinate) if all(cords[:2] == blue_line[0])][0] 1,
        [ i for i,cords in enumerate(point_A_coordinate) if all(cords[:2] == blue_line[1])][0] 1
    ) for blue_line in blue_lines]
 

Вы действительно активизировали игру с нумерацией. Большая часть кода предназначена только для обработки вашей сложной нумерации. Сначала я преобразовал все в соответствующие координаты x, y, а затем обратно, потому что математика намного более интуитивно понятна.

Комментарии:

1. Дорогой @wuerfelfreak, я очень ценю тебя за то, что ты уделил мне время. К сожалению, в данный момент я нахожусь дома (я нахожусь в Европе около 18:00 часов) и не имею доступа к своему компьютеру и данным. Определенно, ваше решение правильное, но в случае возникновения проблем с моими реальными данными, могу ли я добавить комментарии завтра? Еще раз спасибо за вашу поддержку.

2. Нет, проблема вообще. Аналогичное время здесь.

3. Я добавил две строки в конце.

4. Добавлено еще 8 строк.

5. Должно уже в основном работать для поплавков. Только при индексации вам нужно будет выполнить [int(float)]