【问题标题】:Transform a mesh of quads and triangles into a mesh composed of only triangles将四边形和三角形的网格转换为仅由三角形组成的网格
【发布时间】:2017-09-16 15:19:07
【问题描述】:

我不知道如何全面地解释我的问题。所以我给你举个例子……

我有这个数组表示每个四边形或三角形的顶点索引:

>>> faces
array([[0, 1, 2, 3],
       [4, 7, 6, 5],
       [0, 4, 1, 0],
       [1, 5, 6, 2],
       [2, 6, 7, 3],
       [4, 0, 3, 7],
       [1, 4, 5, 0]])

三角形是以0结尾的元素

我想做这样的转换:

>>> faces
array([[0, 1, 2, 3],  #->[[0, 1, 2], [0, 2, 3],
       [4, 7, 6, 5],  #-> [4, 7, 6], [4, 6, 5],
       [0, 4, 1, 0],  #-> [0, 4, 1],
       [1, 5, 6, 2],  #-> [1, 5, 6], [1, 6, 2],
       [2, 6, 7, 3],  #-> [2, 6, 7], [2, 7, 3],
       [4, 0, 3, 7],  #-> [4, 0, 3], [4, 3, 7],
       [1, 4, 5, 0]]) #-> [1, 4, 5]]

那么我怎样才能有效地进行这种转换呢?

我做了一个以不同方式解决它的函数。将quads得到的tirangles放在数组的末尾。

def v_raw_to_tris(tessfaces):
    len_tessfaces = len(tessfaces)
    quad_indices = tessfaces[:, 3].nonzero()[0]
    t3 = np.empty(((len_tessfaces + len(quad_indices)), 3), 'i4')

    t3[:len_tessfaces] = tessfaces[:, :3]
    t3[len_tessfaces:] = tessfaces[quad_indices][:, (0, 2, 3)]

    return t3

但我不希望生成的三角形位于数组的末尾。是的,在原来的四边形前面

【问题讨论】:

  • 因此,输出将具有可变数量的列表,例如第一个 elem 会有两个列表?
  • 或者我们可以把它们都排成一行,总共有 12 行吗?
  • @Divakar,不。每个元素将有 3 个项目
  • 让我换一种说法 - 输出数组的形状必须是什么?
  • 形状为 (-1, 3)。在示例中为 (12, 3)

标签: python arrays performance numpy


【解决方案1】:

我们可以复制每一行,将每一行的一次性移位复制为两行,并在最后屏蔽掉三角形。实现看起来像这样 -

def transform1(a):
    idx = np.flatnonzero(a[:,-1] == 0)
    out0 = np.empty((a.shape[0],2,3),dtype=a.dtype)      

    out0[:,0,1:] = a[:,1:-1]
    out0[:,1,1:] = a[:,2:]

    out0[...,0] = a[:,0,None]

    out0.shape = (-1,3)

    mask = np.ones(out0.shape[0],dtype=bool)
    mask[idx*2+1] = 0
    return out0[mask]

示例运行 -

In [94]: a
Out[94]: 
array([[0, 1, 2, 3],
       [4, 7, 6, 5],
       [0, 4, 1, 0],
       [1, 5, 6, 2],
       [2, 6, 7, 3],
       [4, 0, 3, 7],
       [1, 4, 5, 0]])

In [95]: transform1(a)
Out[95]: 
array([[0, 1, 2],
       [0, 2, 3],
       [4, 7, 6],
       [4, 6, 5],
       [0, 4, 1],
       [1, 5, 6],
       [1, 6, 2],
       [2, 6, 7],
       [2, 7, 3],
       [4, 0, 3],
       [4, 3, 7],
       [1, 4, 5]])

可能的改进

我们可以引入np.lib.stride_tricks.as_strided 来替换out0[:,0,1:] 和out0[:,1,1:] 的两个步骤分配,希望可以改进它,就像这样 -

from numpy.lib.stride_tricks import as_strided
def strided_axis1(a, L):
    s0,s1 = a.strides
    m,n = a.shape
    nL = n-L+1
    return as_strided(a, (m,nL,L),(s0,s1,s1))

def transform2(a):
    idx = np.flatnonzero(a[:,-1] == 0)
    out0 = np.empty((a.shape[0],2,3),dtype=a.dtype)    
    out0[...,1:] = strided_axis1(a[:,1:], 2)    
    out0[...,0] = a[:,0,None]
    out0.shape = (-1,3)
    mask = np.ones(out0.shape[0],dtype=bool)
    mask[idx*2+1] = 0
    return out0[mask]

【讨论】:

  • 我使用我的示例 v_raw_to_tris 和 transform1 和 transform2 的功能在一个极其密集的网格中进行了基准测试。结果是0.056070998899599545, 0.05587086547734543, 0.06008279023626528。 transform1 函数似乎是赢家。我会测试结果
  • 很酷,您正在进行基准测试。我的解决方案在速度方面有什么作用?
  • @Mano-Wii 嗯,这确实是微不足道的改进,我想这是有道理的,因为您已经在原始方法中使用了高效的工具。
  • @Mano-Wii 同样,原始方法是在最后完成分配三角形的简化任务,因此不完全符合预期。所以,我认为这对运行时比较的提议方法是不公平的:)
  • @Chiel,它比上一个效率高得多。现在的时间是0.0885。而trasnform1 和`transform2` 函数分别在同一网格中给出0.0623、0.0700。
【解决方案2】:

这适用于相当紧凑的代码。首先,我们将所有四边形分割成三角形,然后,我们从那些已经是三角形的四边形中删除所有第二个元素。拆分后删除使算法简单。

import numpy as np

a = np.array([[0, 1, 2, 3],
              [4, 7, 6, 5],
              [0, 4, 1, 0],
              [1, 5, 6, 2],
              [2, 6, 7, 3],
              [4, 0, 3, 7],
              [1, 4, 5, 0]])

b = np.empty((a.shape[0], 2, 3))
b[:,0,:] = a[:,(0,1,2)]
b[:,1,:] = a[:,(0,2,3)]
b.shape = (-1, 3)

idx_to_delete = 2*np.flatnonzero(a[:,-1] == 0)+1
b = np.delete(b, idx_to_delete, axis=0)

输出是:

In [4]: print(b)
   [[ 0.  1.  2.]
    [ 0.  2.  3.]
    [ 4.  7.  6.]
    [ 4.  6.  5.]
    [ 0.  4.  1.]
    [ 1.  5.  6.]
    [ 1.  6.  2.]
    [ 2.  6.  7.]
    [ 2.  7.  3.]
    [ 4.  0.  3.]
    [ 4.  3.  7.]
    [ 1.  4.  5.]]

【讨论】:

    猜你喜欢
    • 2012-06-11
    • 2013-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多