2017-09-16 152 views
2

我不知道如何全面地解釋我的問題。所以,我會告訴你一個例子...將四邊形和三角形網格轉換爲僅由三角形組成的網格

我有這樣的陣列表示每個四或三角形的頂點指數:

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

但我不希望產生的三角形在數組的末尾。並且在原來的四邊形前面是

+0

因此,輸出將具有可變數目的列表,例如第一個elem會有兩個列表? – Divakar

+0

或者我們可以把它們全部放在行中,總共給我們12行? – Divakar

+0

@Divakar,不。每個元素將有3個項目 –

回答

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

我做了一個基準,在一個極其密集的網格中,我的例子'v_raw_to_tris'和'transform1'和'transform2'的函數。結果爲'0.056070998899599545,0.05587086547734543,0.06008279023626528'。 'transform1'功能似乎是贏家。我會測試結果 –

+0

很酷,你是基準。我的解決方案在速度方面做了什麼? – Chiel

+0

@ Mano-Wii嗯,這實際上是一個很小的改進,這是有道理的,我猜你已經使用了原始方法的高效工具。 – Divakar

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