スポンサーリンク

Blender Python Meshオブジェクトの頂点のIndexをエッジの接続順にソートする(ループしている場合)

前回は端点がある連続したエッジだったが、エッジがループしている場合のコードも書く。ループしているときはどのエッジでもいいから一本取り出して、その二点から探索を開始する。

探索終了は、探索した結果一番最初の要素が見つかったら終了する。

[1, 2, 3, 6, 7, 5, 4, 0]
import bpy


######################################################
# textオブジェクトの追加
def add_text_numbers(vertexes):

    # 新しいCollrectionを作成
    newCol = bpy.data.collections.new('Vertex Numbers')
    # 現在のシーンにコレクションをリンク
    bpy.context.scene.collection.children.link(newCol)

    for v in range(len(vertexes)):
        
        fontCurve1 = bpy.data.curves.new(type="FONT",name="fontCurve1")
        obj = bpy.data.objects.new("vert[ "+str(v)+" ]",fontCurve1)
        obj.data.body = "" + str(v) # textオブジェクトの内容
        obj.location.x=vertexes[v].co.x
        obj.location.y=vertexes[v].co.y
        obj.location.z=vertexes[v].co.z
        obj.scale=[0.5,0.5,0.5]
              
        newCol.objects.link(obj)


######################################################
# 現在選択中のオブジェクトを取得
def select_object():
   ob = bpy.context.active_object
   
   if ob.type != 'MESH':
       raise TypeError("Active object is not a Mesh")
       
   mesh = ob.data

   #print( len(mesh.edges) )
   #print( len(mesh.vertices) )

   return mesh.vertices, mesh.edges

######################################################
######################################################
# @bref 端点を取得
# @param [in] verts 頂点リスト
# @param [in] edges エッジリスト
# @param [in] target 端点は二つあるので0,1のどちらか
# @return 頂点番号
def get_end_points(verts,edges,target):
    dic = {}

    for v in range(len(verts)):
        dic[v] = 0

    for e in edges:
        dic[e.vertices[0]] += 1
        dic[e.vertices[1]] += 1

    ends = []
    for i in range(len(dic)):
        if dic[ i ] == 1:
            ends.append( i )
    
    #########################
    ## ループしている場合 ###
    if not ends:
        return None
    
    return ends[target]
    

######################################################
######################################################
# @brief vtxを持つエッジのリストを取得
# @param [in] edges エッジリスト
# @param [in] vtx 頂点index
# @return エッジindexの配列
def get_edge_by_point(edges,vtx):
    edgelist = []
    for e in _edges:
        if e.vertices[0] == vtx or e.vertices[1] ==vtx:
            edgelist.append(e.index)
        
    return edgelist

######################################################
######################################################
# @brief V1を持ち、V2を持たないエッジ
# @param [in] V1 頂点index(持つ頂点)
# @param [in] v2 頂点index(持たない頂点)
# @return 見つかったエッジindex
# @retval None そのようなエッジはなかった
def get_edge_V1_but_V2(edges,V1,V2):
    for e in _edges:
        if e.vertices[0] == V1 and e.vertices[1] != V2:
            return e.index
        if e.vertices[1] == V1 and e.vertices[0] != V2:
            return e.index
    return None


######################################################
######################################################
# @brief edgeを構成する2頂点のうち、vertexでないほうの頂点を返す
# @param [in] edge エッジリスト
# @param [in] vertex 基準となる頂点のIndex
# @return 頂点番号
def get_another_point_on_edge(edge,vertex):
    if edge.vertices[0] == vertex:
        return edge.vertices[1]
    if edge.vertices[1] == vertex:
        return edge.vertices[0]
    

######################################################
######################################################
# @brief 一直線に連続した順番の頂点一覧を取得
# @param [in] verts 頂点リスト
# @param [in] edges エッジリスト
# @param [in] order 端点のどちら側から探索するか(0 or 1)
# @return 頂点一覧
def get_connected_vertex_list(verts,edges,order):

    # 結果の格納先
    vlist = []

    # 最初の頂点を取得。「端点」は二つだけ存在するので
    # 結果は二つ求まる(0,1)。そのうちのorder番を取得
    EP = get_end_points(verts,edges,order)
    if EP is not None:
        vlist.append(EP) #その要素が結果の一番目
    
        edgeidxlist = get_edge_by_point(edges,EP)# EPを持つエッジの一覧。要素数1の配列になるはず

        # エッジ最初の頂点を持つエッジ
        endpointedge = edges[edgeidxlist[0]]

        #EP(最初の端点)でない方の頂点を取得
        another = get_another_point_on_edge( endpointedge , EP )
        # 端点を持つエッジの、端点でないほうの頂点は、二番目の頂点
        vlist.append(another)
    
    else:
        #############################
        ## ループしている場合 #######
        if order == 0:
            vlist.append( edges[0].vertices[0] )
            vlist.append( edges[0].vertices[1] )
        else:
            vlist.append( edges[0].vertices[1] )
            vlist.append( edges[0].vertices[0] )
            

    # 無限ループを使うのでループ上限を設けておく
    looplimit = 100

    while True:

        # 前回の前回見つけた頂点
        before = vlist[len(vlist)-2]

        # 前回見つけた頂点。この頂点の次の頂点を探したい
        now = vlist[len(vlist)-1]
        
        #nowを持ち、beforeを持たないエッジを検索
        nextedge = get_edge_V1_but_V2(edges,now,before)
        
        # 端点には「nowを持ち、beforeを持たないエッジ」がないので、Noneが入っている
        if nextedge is None:
            break
        
        #nextedgeの、nowでない方の頂点を取得
        next = get_another_point_on_edge( edges[nextedge] , now )
        
        #####################################
        ## ループしている場合 ###############
        if next == vlist[0]:
            break
        
        vlist.append(next)

        looplimit -= 1
        if looplimit == 0:
            break

    return vlist


# 頂点群を取得
ret = select_object()

_verts = ret[0]
_edges = ret[1]

# 頂点番号のテキストオブジェクトを追加
add_text_numbers(_verts)

vtx_c_list = get_connected_vertex_list(_verts,_edges,0)
print(vtx_c_list)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: