在 matplotlib 中使用三角测量时,如何处理在几何图形边缘之间形成的(不需要的)三角形

use*_*081 6 python mesh matplotlib

我有一个用空间中的 (x,y) 点列表定义的几何图形。我想用这些数据创建一个三角形网格,因此我尝试了matplotlib 中的三角测量函数来实现此目的。然而,由于我的几何体有一些曲线,该算法在我的零件的边缘之间生成不需要的三角形:

图像

红色曲线是我的几何图形的边缘。

有什么办法可以解决这个问题吗?也许三角测量功能不是我需要的,在这种情况下,您对使用什么有什么建议吗?

以下代码来自该示例。在示例中,他们通过显式命名三个点来定义三角形,而不是我想通过调用函数来使用的 Delaunay 三角剖分triang = tri.Triangulation(x, y),这将给我提供与原始图片相同的行为。

import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np

xy = np.asarray([
    [-0.101, 0.872], [-0.080, 0.883], [-0.069, 0.888], [-0.054, 0.890],
    [-0.045, 0.897], [-0.057, 0.895], [-0.073, 0.900], [-0.087, 0.898],
    [-0.090, 0.904], [-0.069, 0.907], [-0.069, 0.921], [-0.080, 0.919],
    [-0.073, 0.928], [-0.052, 0.930], [-0.048, 0.942], [-0.062, 0.949],
    [-0.054, 0.958], [-0.069, 0.954], [-0.087, 0.952], [-0.087, 0.959],
    [-0.080, 0.966], [-0.085, 0.973], [-0.087, 0.965], [-0.097, 0.965],
    [-0.097, 0.975], [-0.092, 0.984], [-0.101, 0.980], [-0.108, 0.980],
    [-0.104, 0.987], [-0.102, 0.993], [-0.115, 1.001], [-0.099, 0.996],
    [-0.101, 1.007], [-0.090, 1.010], [-0.087, 1.021], [-0.069, 1.021],
    [-0.052, 1.022], [-0.052, 1.017], [-0.069, 1.010], [-0.064, 1.005],
    [-0.048, 1.005], [-0.031, 1.005], [-0.031, 0.996], [-0.040, 0.987],
    [-0.045, 0.980], [-0.052, 0.975], [-0.040, 0.973], [-0.026, 0.968],
    [-0.020, 0.954], [-0.006, 0.947], [ 0.003, 0.935], [ 0.006, 0.926],
    [ 0.005, 0.921], [ 0.022, 0.923], [ 0.033, 0.912], [ 0.029, 0.905],
    [ 0.017, 0.900], [ 0.012, 0.895], [ 0.027, 0.893], [ 0.019, 0.886],
    [ 0.001, 0.883], [-0.012, 0.884], [-0.029, 0.883], [-0.038, 0.879],
    [-0.057, 0.881], [-0.062, 0.876], [-0.078, 0.876], [-0.087, 0.872],
    [-0.030, 0.907], [-0.007, 0.905], [-0.057, 0.916], [-0.025, 0.933],
    [-0.077, 0.990], [-0.059, 0.993]])
x = np.degrees(xy[:, 0])
y = np.degrees(xy[:, 1])

triang = tri.Triangulation(x, y)
fig1, ax1 = plt.subplots()
ax1.set_aspect('equal')
ax1.triplot(triang, 'bo-', lw=1)
Run Code Online (Sandbox Code Playgroud)

Imp*_*est 7

如果您有内部形状的轮廓来绘制三角剖分,您可以应用@ThomasK\xc3\xbchn 的答案。

\n\n

否则,点之间可能存在最大距离,超过该距离的三角形不应被考虑在内。在这种情况下,您可以掩盖这些三角形。

\n\n
import matplotlib.pyplot as plt\nimport matplotlib.tri as tri\nimport numpy as np\n\nxy = np.asarray([\n    [-0.101, 0.872], [-0.080, 0.883], [-0.069, 0.888], [-0.054, 0.890],\n    [-0.045, 0.897], [-0.057, 0.895], [-0.073, 0.900], [-0.087, 0.898],\n    [-0.090, 0.904], [-0.069, 0.907], [-0.069, 0.921], [-0.080, 0.919],\n    [-0.073, 0.928], [-0.052, 0.930], [-0.048, 0.942], [-0.062, 0.949],\n    [-0.054, 0.958], [-0.069, 0.954], [-0.087, 0.952], [-0.087, 0.959],\n    [-0.080, 0.966], [-0.085, 0.973], [-0.087, 0.965], [-0.097, 0.965],\n    [-0.097, 0.975], [-0.092, 0.984], [-0.101, 0.980], [-0.108, 0.980],\n    [-0.104, 0.987], [-0.102, 0.993], [-0.115, 1.001], [-0.099, 0.996],\n    [-0.101, 1.007], [-0.090, 1.010], [-0.087, 1.021], [-0.069, 1.021],\n    [-0.052, 1.022], [-0.052, 1.017], [-0.069, 1.010], [-0.064, 1.005],\n    [-0.048, 1.005], [-0.031, 1.005], [-0.031, 0.996], [-0.040, 0.987],\n    [-0.045, 0.980], [-0.052, 0.975], [-0.040, 0.973], [-0.026, 0.968],\n    [-0.020, 0.954], [-0.006, 0.947], [ 0.003, 0.935], [ 0.006, 0.926],\n    [ 0.005, 0.921], [ 0.022, 0.923], [ 0.033, 0.912], [ 0.029, 0.905],\n    [ 0.017, 0.900], [ 0.012, 0.895], [ 0.027, 0.893], [ 0.019, 0.886],\n    [ 0.001, 0.883], [-0.012, 0.884], [-0.029, 0.883], [-0.038, 0.879],\n    [-0.057, 0.881], [-0.062, 0.876], [-0.078, 0.876], [-0.087, 0.872],\n    [-0.030, 0.907], [-0.007, 0.905], [-0.057, 0.916], [-0.025, 0.933],\n    [-0.077, 0.990], [-0.059, 0.993]])\nx = np.degrees(xy[:, 0])\ny = np.degrees(xy[:, 1])\n\ntriang = tri.Triangulation(x, y)\n\nfig1, ax1 = plt.subplots()\nax1.set_aspect(\'equal\')\n\n# plot all triangles\nax1.triplot(triang, \'bo-\', lw=0.2)\n\n# plot only triangles with sidelength smaller some max_radius\nmax_radius = 2\ntriangles = triang.triangles\n\n# Mask off unwanted triangles.\nxtri = x[triangles] - np.roll(x[triangles], 1, axis=1)\nytri = y[triangles] - np.roll(y[triangles], 1, axis=1)\nmaxi = np.max(np.sqrt(xtri**2 + ytri**2), axis=1)\ntriang.set_mask(maxi > max_radius)\n\nax1.triplot(triang, color="indigo", lw=2.6)\n\n\nplt.show()\n
Run Code Online (Sandbox Code Playgroud)\n\n

窄线显示所有三角形(点的凸包),粗线仅显示那些边长不大于某些最大值(在本例中选择为2)的三角形。

\n\n

在此输入图像描述

\n\n

该线程可能同样相关:matplotlibcontour/contourf of **concave** non-gridded data

\n


Tho*_*ühn 5

If the shape of the geometry is well defined, say by a curve, one can check for each triangle whether it lies within the shape or not. One can then define a mask and mask out undesired triangles. I found a solution using shapely, where define a polygon for the original shape (outline) and a polygon for each resulting triangle of Triangulation(), for which I then check whether it lies inside outline or not:

import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np

import shapely
from shapely.geometry import Polygon as sPolygon


fig, (ax1,ax2) = plt.subplots(ncols=2)
ax1.set_aspect('equal')
ax2.set_aspect('equal')

##setting up basic shape
phi = np.linspace(0,2*np.pi,20)
r = 1 + 2*np.sin(phi)**2
x = np.cos(phi)*r
y = np.sin(phi)*r
ax1.plot(x,y,'ro-', lw=3, ms=6, zorder= 1, label='edge')
ax2.plot(x,y,'ro-', lw=3, ms=6, zorder= 1)


##original triangulation
triang1 = tri.Triangulation(x, y)
ax1.triplot(triang1, 'ko--', lw=1, ms=4, zorder=2, label='all')

##masking
outline = sPolygon(zip(x,y))
mask = [
    not outline.contains(sPolygon(zip(x[tri], y[tri])))
    for tri in triang1.get_masked_triangles()
]
triang1.set_mask(mask)
ax1.triplot(triang1, 'b-', lw=1, zorder=3, label='inner')

##adding more points
x_extra = np.random.rand(30)*(x.max()-x.min())+x.min()
y_extra = np.random.rand(30)*(y.max()-y.min())+y.min()

x = np.concatenate([x,x_extra])
y = np.concatenate([y,y_extra])

triang2 = tri.Triangulation(x,y)
ax2.triplot(triang2, 'ko--', lw=1, ms=4,  zorder=2)

##masking
mask = [
    not outline.contains(sPolygon(zip(x[tri], y[tri])))
    for tri in triang2.get_masked_triangles()
]
triang2.set_mask(mask)
ax2.triplot(triang2, 'b-', lw=1, zorder=3)

fig.legend()
plt.show()
Run Code Online (Sandbox Code Playgroud)

The result of the code looks something like this:

上面代码的结果

我不太确定OP想要什么,所以在左侧我只使用边缘的点,而在右侧我添加了一些随机的额外点进行三角测量。图中,形状的轮廓以红色绘制,Delaunay 三角剖分的原始结果以黑色虚线绘制,蒙版三角剖分以蓝色绘制。

编辑

我刚刚注意到,显然过滤后的右侧图片中不包含轮廓点之一。这一定是由于数字不准确造成的。解决此问题的一种方法是使用buffer()命令稍微增加轮廓的大小。这样的事情似乎适合当前的问题:

outline = sPolygon(zip(x,y)).buffer(.01)
Run Code Online (Sandbox Code Playgroud)

但实际的缓冲量可能需要调整。