将四边形和三角形网格转换为仅由三角形组成的网格

时间:2017-09-16 15:19:07

标签: python arrays performance numpy

我不知道如何全面地解释我的问题。所以我会告诉你一个例子......

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

>>> 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]]

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

我做了一个以不同方式解决它的功能。将四边形获得的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

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

2 个答案:

答案 0 :(得分: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]

答案 1 :(得分:0)

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

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.]]