ポリゴンメッシュ内の直方体を構成する面を選択 (スクリプト)

ブラウザで選択したポリゴンメッシュのうち、
8頂点/6面で構成される直方体の面を選択するスクリプトです。


import numpy
import math

scene = xshade.scene()

# ----------------------------------------------------------.
# ポリゴンメッシュの隣接する面をたどり、面ごとのシェル番号を割り当て.
# @param[in] shape  対象ポリゴンメッシュ.
# @return  面ごとのシェル番号(0-)の配列.
# ----------------------------------------------------------.
def getMeshShellIndex (shape):
    if shape.type != 7:     # ポリゴンメッシュでない場合.
        return None

    facesCou = shape.number_of_faces
    versCou  = shape.total_number_of_control_points

    faceGIndexList = [-1] * facesCou

    # 頂点が共有する4頂点を持つ面のリストを作成.
    vFacesList = []
    for i in range(versCou):
        vFacesList.append([])
    
    for i in range(facesCou):
        f = shape.face(i)
        vCou = f.number_of_vertices
        if vCou < 3:
            continue
        for j in range(vCou):
            vIndex = f.vertex_indices[j]
            vFacesList[vIndex].append(i)

    # 隣接する面をたどり、インデックスを割り当てていく.
    fNewIndex = 0
    for fLoop in range(facesCou):
        if faceGIndexList[fLoop] >= 0:
            continue

        f = shape.face(fLoop)
        vCou = f.number_of_vertices
        if vCou < 3:
            continue

        faceIList = [fLoop]

        while len(faceIList):
            fCurIndex = faceIList[0]

            if faceGIndexList[fCurIndex] >= 0:
                faceIList.pop(0)
                continue

            f = shape.face(fCurIndex)
            vCou = f.number_of_vertices
            if vCou < 3:
                faceIList.pop(0)
                continue

            faceGIndexList[fCurIndex] = fNewIndex

            for i in range(vCou):
                i1 = f.vertex_indices[i]
                i2 = f.vertex_indices[(i + 1) % vCou]

                fList1 = vFacesList[i1]
                for j in range(len(fList1)):
                    fI = fList1[j]
                    if fI == fLoop or faceGIndexList[fI] >= 0:
                        continue

                    iCou = 0
                    f2 = shape.face(fI)
                    vCou2 = f2.number_of_vertices
                    if vCou2 < 3:
                        continue
                    
                    for k in range(vCou2):
                        vI = f2.vertex_indices[k]
                        if vI == i1 or vI == i2:
                            iCou += 1
                    
                    if iCou == 2:
                        faceIList.append(fI)

            faceIList.pop(0)
        fNewIndex += 1

    return faceGIndexList

# ----------------------------------------------------------.
# ポリゴンメッシュの6つの四角形面が直方体を構成しているかチェック.
# @param[in]  shape     対象形状.
# @param[in]  faceList  直方体の6面のインデックス.
# @return 直方体の場合はTrue, その後に6面の対面の番号を0-2で入れる配列.
# ----------------------------------------------------------.
def checkBox (shape, faceList):
    if len(faceList) != 6:
        return False, None

    # 向かい合う面の組み合わせが3つあれば直方体と判断.
    fDList = [-1] * 6
    index = 0
    for i in range(6):
        if fDList[i] >= 0:
            continue

        # 面法線.
        fNormal1 = shape.get_plane_equation(faceList[i])
        fNormal1 = numpy.array([fNormal1[0], fNormal1[1], fNormal1[2]])

        for j in range(i + 1, 6):
            if fDList[j] >= 0:
                continue
        
            # 面法線.
            fNormal2 = shape.get_plane_equation(faceList[j])
            fNormal2 = numpy.array([fNormal2[0], fNormal2[1], fNormal2[2]])

            # fNormal1とfNormal2が対面になっているか.
            v = numpy.dot(fNormal1, fNormal2)
            if math.fabs(v) > 0.999:
                fDList[i] = index
                fDList[j] = index
                index += 1
                break

    if index != 3:
        return False, None

    return True, fDList

# ----------------------------------------------------------.
# ポリゴンメッシュから直方体を構成する面番号の配列を返す.
# @param[in]  shape  対象形状.
# @return 直方体を構成する面の配列を [][6]で返す.
# ----------------------------------------------------------.
def getBoxFaces (shape):
    if shape.type != 7:     # ポリゴンメッシュでない場合.
        return None

    shape.setup_plane_equation()

    facesCou = shape.number_of_faces
    versCou  = shape.total_number_of_control_points
    if facesCou < 6 or versCou < 8:
        return None

    # 面ごとのシェル番号を取得.
    faceShellIndex = getMeshShellIndex(shape)

    maxShellIndex = -1
    for shellIndex in range(facesCou):
        if faceShellIndex[shellIndex] > maxShellIndex:
            maxShellIndex = faceShellIndex[shellIndex]
    if maxShellIndex < 0:
        return None

    # 直方体を構成する四角形面の面番号の配列を取得.
    retBoxList = []
    for shellIndex in range(maxShellIndex + 1):
        fList = []
        for i in range(len(faceShellIndex)):
            if faceShellIndex[i] == shellIndex:
                fList.append(i)

        # 6面で構成されるか.
        fCou = len(fList)
        if fCou != 6:
            continue

        # すべての面が四角形で構成されるか.
        fCou2 = 0
        for i in range(fCou):
            f = shape.face(fList[i])
            if f.number_of_vertices == 4:
                fCou2 += 1
        
        if fCou2 != 6:
            continue

        # fListに格納された面が直方体を構成するかチェック.
        retV = checkBox(shape, fList)
        if retV[0]:
            retBoxList.append(fList)

    return retBoxList

# -------------------------------------.

# 形状編集モード + 面選択モードに移行.
scene.enter_modify_mode()
scene.selection_mode = 0

for shape in scene.active_shapes:
    # すべての選択を解除.
    shape.select_all_control_points(False)

    # ポリゴンメッシュで直方体を構成する面番号を取得.
    boxList = getBoxFaces(shape)
    if len(boxList) > 0:
        print "[" + shape.name + "] : 直方体の数 " + str(len(boxList))

        # 直方体を構成する面を選択.
        for faceList in boxList:
            for faceIndex in faceList:
                shape.face(faceIndex).active = True

scene.update_figure_window()

使い方

ブラウザで調査対象のポリゴンメッシュを選択します。

上記のスクリプトをスクリプトウィンドウにコピー&ペーストし実行します。
以下のように、8頂点/6面で構成される直方体を構成する面のみ選択されます。

この記事のURLとタイトルをコピーする
Translate »