[英]Extrude a concave, complex polygon in PyVista
我希望采用凹形和復雜(包含孔)多邊形並將其“垂直”擠壓成多面體,純粹是為了可視化。 我從一個勻稱的Polygon
開始,如下所示:
poly = Polygon(
[(0,0), (10,0), (10,10), (5,8), (0,10), (1,7), (0,5), (1,3)],
holes=[
[(2,2),(4,2),(4,4),(2,4)],
[(6,6), (7,6), (6.5,6.5), (7,7), (6,7), (6.2,6.5)]])
我在 matplotlib 中正確地將 plot(將外部坐標重新定向為順時針,並將孔坐標重新定向為逆時針)為:
然后,我試圖使用PyVista將這個多邊形渲染到頁面外(沿着z
)。 有一些障礙; PyVista 不直接支持其PolyData
類型的凹凸輸入。 所以我們首先創建一個簡單(無孔)凸多邊形的擠壓:
def extrude_simple_polygon(xy, z0, z1):
# force counter-clockwise ordering, so PyVista interprets polygon correctly
xy = _reorient_coords(xy, clockwise=False)
# remove duplication of first & last vertex
xyz0 = [(x,y,z0) for x,y in xy]
if (xyz0[0] == xyz0[-1]):
xyz0.pop()
# use delaunay, as per https://github.com/pyvista/pyvista/discussions/2398
base_vert = [len(xyz0)] + list(range(len(xyz0)))
base_data = pyvista.PolyData(xyz0, base_vert)
base_mesh = base_data.delaunay_2d(edge_source=base_data)
vol_mesh = base_mesh.extrude((0, 0, z1-z0), capping=True)
# force triangulation, so PyVista allows boolean_difference
return vol_mesh.triangulate()
當依次擠壓外部多邊形及其每個內部多邊形時,請觀察此方法:
extrude_simple_polygon(list(poly.exterior.coords), 0, 5).plot()
extrude_simple_polygon(list(poly.interiors[0].coords), 0, 5).plot()
extrude_simple_polygon(list(poly.interiors[1].coords), 0, 5).plot()
我推斷要創建原始復雜多邊形的擠壓,我可以計算boolean_difference
。 唉,結果
outer_vol = extrude_simple_polygon(list(poly.exterior.coords), 0, 5)
for hole in poly.interiors:
hole_vol = extrude_simple_polygon(list(hole.coords), 0, 5)
outer_vol = outer_vol.boolean_difference(hole_vol)
outer_vol.plot()
是錯誤的:
該文檔建議通過plot_normals
檢查法線,揭示所有擠壓體積都有向內指向(或者,意外的)法線:
extrude
文檔沒有提及擠出表面法線或原始 object(在本例中為多邊形)方向。
我們可以原諒我們期望我們的多邊形必須是clockwise ,所以我們在extrude_simple_polygon
的第一行設置clockwise=True
並重試。 唉, PolyData
現在誤解了我們的基本多邊形; 調用base_mesh.plot()
顯示(應該看起來像我們原來的藍色外多邊形):
帶擠壓
你非常接近。 您需要做的是對delaunay_2d()
進行一次調用,將所有三個多邊形(即封閉的一個和兩個孔)作為邊源(循環源?)。 每個多邊形都有面(而不是線)也很重要; 這就是可以加強孔洞的多孔性的原因。
這是您輸入的完整示例(我手動翻轉了孔的方向;您似乎有一個_reorient_coords()
助手,您應該改用):
import pyvista as pv
# coordinates of enclosing polygon
poly_points = [
(0, 0), (10, 0), (10, 10), (5, 8), (0, 10), (1, 7), (0, 5), (1, 3),
]
# hole point order hard-coded here; use your _reorient_coords() function
holes = [
[(2, 2), (4, 2), (4, 4), (2, 4)][::-1],
[(6, 6), (7, 6), (6.5, 6.5), (7, 7), (6, 7), (6.2, 6.5)][::-1],
]
z0, z1 = 0.0, 5.0
def points_2d_to_poly(points, z):
"""Convert a sequence of 2d coordinates to a polydata with a polygon."""
faces = [len(points) + 1, *range(len(points)), 0]
poly = pv.PolyData([p + (z,) for p in points], faces=faces)
return poly
# bounding polygon
polygon = points_2d_to_poly(poly_points, z0)
# add all holes
for hole_points in holes:
polygon += points_2d_to_poly(hole_points, z0)
# triangulate poly with all three subpolygons supplying edges
# (relative face orientation is critical here)
polygon_with_holes = polygon.delaunay_2d(edge_source=polygon)
# extrude
holey_solid = polygon_with_holes.extrude((0, 0, z1 - z0), capping=True)
holey_solid.plot()
這是多邊形預擠壓的頂視圖:
plotter = pv.Plotter()
plotter.add_mesh(polygon_with_holes, show_edges=True, color='cyan')
plotter.view_xy()
plotter.show()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.