Учитывая набор вершин и граней треугольника, отдельные объекты и образуют отдельные сетки - PullRequest
2 голосов
/ 03 мая 2020

Редактировать: я написал более краткую версию этого вопроса здесь , но я сохраняю этот пост, потому что это полное объяснение.

Учитывая массив 3D numpy, марширующих кубов могут образовать 3D объект вокруг некоторого порога.

import numpy as np
from skimage import measure

A = np.zeros((12,12,12))
#A[A<1] = -1
for i in np.arange(1,2):
    for j in np.arange(1,2):
        for k in np.arange(1,2):
            A[i,j,k] = 10

for i in np.arange(8,9):
    for j in np.arange(8,9):
        for k in np.arange(8,9):
            A[i,j,k] = 10

verts, faces, normals, values = measure.marching_cubes_lewiner(A,1)

# which returns 

verts = [[0.1, 1.,  1. ]  [1.,  1.,  0.1]  [1.,  0.1, 1. ]  [1.,  1.,  1.9]  [1.,  1.9, 1. ]
 [1.9, 1.,  1. ]  [7.1, 8.,  8. ]  [8.,  8.,  7.1]  [8.,  7.1, 8. ]  [8.,  8.,  8.9]
 [8.,  8.9, 8. ]  [8.9, 8.,  8. ]]

faces = [[ 2,  1,  0]  [ 0,  3,  2]  [ 1,  4,  0]  [ 0,  4,  3]  [ 5,  1,  2]  [ 3,  5,  2]
 [ 5,  4,  1]  [ 4,  5,  3]  [ 8,  7,  6]  [ 6,  9,  8]  [ 7, 10,  6]  [ 6, 10,  9]
 [11,  7,  8]  [ 9, 11,  8]  [11, 10,  7]  [10, 11,  9]]

Это может быть построено на графике:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from mpl_toolkits.mplot3d import Axes3D

mesh = Poly3DCollection(verts[faces])

mesh.set_edgecolor('k')
mesh.set_facecolor('b')
ax.set_xlim(0,10)
ax.set_ylim(0,10)
ax.set_zlim(0,12)

Возвращение этого прекрасного трехмерного изображения:

Tetrahedrons

Я использую алгоритм для разделения эти объекты, используя мой собственный код (см. ниже) и получают:

graph1 = {(1.0, 1.0, 0.10000000149011612), (1.899999976158142, 1.0, 1.0), (0.10000000149011612, 1.0, 1.0), (1.0, 1.899999976158142, 1.0), (1.0, 0.10000000149011612, 1.0), (1.0, 1.0, 1.899999976158142)}

graph2 = {(8.899999618530273, 8.0, 8.0), (8.0, 8.899999618530273, 8.0), (7.099999904632568, 8.0, 8.0), (8.0, 8.0, 7.099999904632568), (8.0, 7.099999904632568, 8.0), (8.0, 8.0, 8.899999618530273)}

Теперь проблема в том, что, хотя я нашел вершины, составляющие каждый граф, у меня больше нет простого способа создания отдельные 3D-сетки для каждого объекта. Если раньше для создания me sh использовалось verts[faces], то не очевидно, как соотносить каждую graph с faces для создания трех angular сеток. Я пытался решить эту проблему, но не удалось. Например:

verts1 = verts[0:6]
faces1 = faces[0:6] 
mesh = Poly3DCollection(verts1[faces1])

Это не работает. Я думаю, что ключом было бы найти лица, которые соответствуют каждому объекту. Если бы это было сделано, это могло бы работать. Например, наш первый граф включает в себя только вершины с 1 по 6. Поэтому нам нужны только faces, которые ссылаются на эти вершины. В качестве демонстрации можно воспроизвести первый граф graph1 (без графа 2), используя:

faces1 = faces[0:8]
mesh = Poly3DCollection(verts[faces1])
# and plot like above

Если бы я мог записать не только вершины, но и их индекс, я мог бы отсортировать faces для тех, которые относятся к этому объекту. Я объясню. Первая проблема, у меня нет показателей. Это мой способ сортировки объектов. Сначала мы создаем список строк (или edgelist), затем создаем их кортежи, а затем используем networkx для поиска подключенных компонентов.

# create linelist
linelist = []
for idx, vert in enumerate(faces):  
    for i,x in enumerate(vert):
        l = [np.ndarray.tolist(verts[faces[idx][i]]), np.ndarray.tolist(verts[faces[idx][(i+1)%len(vert)]])] # connect the verts of the triangle
        linelist.append(l)  # add to the line list

# Creates graph
tmp = [tuple(tuple(j) for j in i) for i in linelist]
graph = nx.Graph(tmp)
graphs = []
i=0
for idx, graph in enumerate(sorted(nx.connected_components(graph),key = len, reverse = True)):
    graphs.append((graph))
    print("Graph ",idx," corresponds to vertices: ",graph,'\n\n',file=open("output.txt","a"))         
    i+=1

Я не вижу, как networkx также может записывать индекс каждой вершины.

Во-вторых, возможно, что faces, относящийся к каждому объекту, не пересекается, т. Е. Это может быть faces[0:4] + faces[66] + faces[100:110]. Тем не менее, это может быть преодолено.

Предполагая, что мы можем сгенерировать список индексов для каждого графа, основная проблема заключается в поиске эффективного способа определения того, какие грани относятся к этим вершинам. Мое решение работает для этого набора объектов, но не для более сложных аранжировок (которые я могу предоставить). Это также чрезвычайно медленно. Тем не менее, вот оно:

objects  = []
obj = []
i = 0
for idx, face in enumerate(M):
    if i == 0:
        obj.append(face)
        i = i + 1
    else:
        if np.isin(face,obj).any():
            obj.append(face)
        else: 
            objects.append(obj.copy())
            obj = []
            obj.append(face)
            i = 0
        if idx == len(M)-1:
            objects.append(obj.copy())

Если вы прочитали это далеко, я действительно впечатлен сообществом. Я думаю, что есть эффективный способ сделать это, возможно, с networkx, но я не нашел его.

Требуемый вывод : Я хочу отсортировать грани в связанные компоненты так же, как я сортирую вершины. graph1 = faces[x1] + faces[x2] + ... + faces[xn].

Редактировать: Если кто-то может помочь мне с кодированием, у меня есть идея (частично благодаря @Ehsan). После разделения на связанные компоненты и нахождения графиков, вершины каждого из них можно хэшировать, чтобы найти исходный индекс. Затем можно найти faces, который включает хотя бы один из этих индексов (поскольку, если он содержит одну вершину, он должен быть гранью graph). Я не уверен, насколько эффективно это будет. Я бы с удовольствием, если бы был быстрый обходной путь для сети.

1 Ответ

0 голосов
/ 07 мая 2020

@ Пол Бродерсон ответил на этот вопрос { ссылка }

Я положу его здесь только для эстетики:

#!/usr/bin/env python
"""
Given a list of triangles, find the connected components.

https://stackoverflow.com/q/61584283/2912349
"""
import itertools
import networkx as nx

faces = [[ 2,  1,  0],  [ 0,  3,  2],  [ 1,  4,  0],  [ 0,  4,  3],  [ 5,  1,  2],  [ 3,  5,  2],
         [ 5,  4,  1],  [ 4,  5,  3],  [ 8,  7,  6],  [ 6,  9,  8],  [ 7, 10,  6],  [ 6, 10,  9],
         [11,  7,  8],  [ 9, 11,  8],  [11, 10,  7],  [10, 11,  9]]

#create graph
edges = []
for face in faces:
    edges.extend(list(itertools.combinations(face, 2)))
g = nx.from_edgelist(edges)

# compute connected components and print results
components = list(nx.algorithms.components.connected_components(g))

for component in components:
    print(component)

# {0, 1, 2, 3, 4, 5}
# {6, 7, 8, 9, 10, 11}

# separate faces by component
component_to_faces = dict()
for component in components:
    component_to_faces[tuple(component)] = [face for face in faces if set(face) <= component] # <= operator tests for subset relation

for component, component_faces in component_to_faces.items():
    print(component, component_faces)
# (0, 1, 2, 3, 4, 5) [[2, 1, 0], [0, 3, 2], [1, 4, 0], [0, 4, 3], [5, 1, 2], [3, 5, 2], [5, 4, 1], [4, 5, 3]]
# (6, 7, 8, 9, 10, 11) [[8, 7, 6], [6, 9, 8], [7, 10, 6], [6, 10, 9], [11, 7, 8], [9, 11, 8], [11, 10, 7], [10, 11, 9]] 
...