簡體   English   中英

如何從多數據中提取邊緣作為連接特征?

[英]How to extract edges from polydata as connected features?

我有一個多數據結構及其提取的邊,但使用extract_feature_edges function 計算為未連接的單元格(分隔線)。

是否可以將這些單元(線)從它們的共同點連接起來,然后獲得不同的特征(陸地、島嶼,例如您在圖像中看到的——南極洲、澳大利亞……——順便說一句,它們是古大陸)?

在簡歷中,我想從我的網格及其邊緣中提取不同的土地部分作為單獨的多數據。 我已經嘗試使用 python 模塊 shapely 和多邊形化 function,它可以工作但不適用於 3D 坐標( https://shapely.readthedocs.io/en/latest/reference/shapely.polygonize.html )。

import pyvista as pv

! wget -q -nc https://thredds-su.ipsl.fr/thredds/fileServer/ipsl_thredds/brocksce/pyvista/mesh.vtk
mesh = pv.PolyData('mesh.vtk')
edges = mesh.extract_feature_edges(boundary_edges=True)

pl = pv.Plotter()

pl.add_mesh(pv.Sphere(radius=0.999, theta_resolution=360, phi_resolution=180))
pl.add_mesh(mesh, show_edges=True, edge_color="gray")
pl.add_mesh(edges, color="red", line_width=2)

viewer = pl.show(jupyter_backend='pythreejs', return_viewer=True)
display(viewer)

在此處輸入圖像描述

任何的想法?

這是一個使用 vtk.vtkStripper() 將連續線段連接成折線的解決方案。 請參閱來自https://discourse.vtk.org/t/get-a-continuous-line-from-a-polydata-structure/9864的線程

import pyvista as pv
import vtk
import random

! wget -q -nc https://thredds-su.ipsl.fr/thredds/fileServer/ipsl_thredds/brocksce/pyvista/mesh.vtk
mesh = pv.PolyData('mesh.vtk')
edges = mesh.extract_feature_edges(boundary_edges=True)

pl = pv.Plotter()

pl.add_mesh(pv.Sphere(radius=0.999, theta_resolution=360, phi_resolution=180))
pl.add_mesh(mesh, show_edges=True, edge_color="gray")

regions = edges.connectivity()
regCount = len(set(pv.get_array(regions, name="RegionId")))

connectivityFilter = vtk.vtkPolyDataConnectivityFilter()
stripper = vtk.vtkStripper()

for r in range(regCount):
    connectivityFilter.SetInputData(edges)
    connectivityFilter.SetExtractionModeToSpecifiedRegions()
    connectivityFilter.InitializeSpecifiedRegionList()
    connectivityFilter.AddSpecifiedRegion(r)
    connectivityFilter.Update()
    
    stripper.SetInputData(connectivityFilter.GetOutput())
    stripper.SetJoinContiguousSegments(True)
    stripper.Update()
    reg = stripper.GetOutput()
    
    random_color = "#"+''.join([random.choice('0123456789ABCDEF') for i in range(6)])
    pl.add_mesh(reg, color=random_color, line_width=4)

viewer = pl.show(jupyter_backend='pythreejs', return_viewer=True)
display(viewer)

在 github 討論中已經出現過。 結論是 PyVista 沒有內置任何東西來重新排序邊緣,但可能有第三方庫可以做到這一點( 這個答案提到libigl ,但我沒有這方面的經驗)。

我對如何解決這個問題有一些想法,但有人擔心這種助手在一般情況下的適用性。 但是,在您的特定情況下,我們知道每條邊都是一個閉環,並且它們不是很多,因此我們不必擔心性能(尤其是 memory 足跡)那么多。

這是一種手動方法,通過構建鄰接圖並步行直到我們結束每個循環的起點來重新排序邊緣:

from collections import defaultdict

import pyvista as pv

# load example mesh
mesh = pv.read('mesh.vtk')

# get edges
edges = mesh.extract_feature_edges(boundary_edges=True)

# build undirected adjacency graph from edges (2-length lines)
# (potential performance improvement: use connectivity to only do this for each closed loop)
# (potentially via calling edges.split_bodies())
lines = edges.lines.reshape(-1, 3)[:, 1:]
adjacency = defaultdict(set)  # {2: {1, 3}, ...} if there are lines from point 2 to point 1 and 3
for first, second in lines:
    adjacency[first].add(second)
    adjacency[second].add(first)

# start looping from whichever point, keep going until we run out of adjacent points
points_left = set(range(edges.n_points))
loops = []
while points_left:
    point = points_left.pop()  # starting point for next loop
    loop = [point]
    loops.append(loop)
    while True:
        # keep walking the loop
        neighb = adjacency[point].pop()
        loop.append(neighb)
        if neighb == loop[0]:
            # this loop is done
            break
        # make sure we never backtrack
        adjacency[neighb].remove(point)
        # bookkeeping
        points_left.discard(neighb)
        point = neighb

# assemble new lines based on the existing ones, flatten
lines = sum(([len(loop)] + loop for loop in loops), [])

# overwrite the lines in the original edges; optionally we could create a copy here
edges.lines = lines

# edges are long, closed loops by construction, so it's probably correct
# plot each curve with an individual colour just to be safe
plotter = pv.Plotter()
plotter.add_mesh(pv.Sphere(radius=0.999))
plotter.add_mesh(edges, scalars=range(edges.n_cells), line_width=3, show_scalar_bar=False)
plotter.enable_anti_aliasing('msaa')
plotter.show()

此代碼用定義每個循環的 14 條較大的線替換了您原來的 1760 條 2 長線。 不過,您必須要小心一點:在澳大利亞北部,您有一個自相交的循環:

帶有彩色大陸邊緣的白色地球儀;還可以看到一條 8 字形的自相交路徑

交點出現 4 次而不是 2 次。這意味着我的強力求解器沒有給出明確定義的結果:它會隨機選擇交點,如果運氣不好,我們從交點開始循環點算法可能會失敗。 讓它更健壯留給讀者作為練習(我關於將邊緣拆分為單個邊緣的評論可能有助於解決這個問題)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM