エッジIDをループ毎にグループ化する

投稿者: | 2017/05/15

今回は選択エッジをエッジループ毎にグループ化する方法を紹介します。

例えば、下図左のように選択した場合、右のようにエッジループをグループ化します。

エッジからボーンチェインを作成したい場合など、エッジが連続したループになっている必要がある時に便利です。

残念ながらEdit_Polyモディファイアには対応していません。Editable_Poly専用です。

コード

-- 指定したEditable_Polyエッジをループ毎にグループ化する
-- Return: #(EdgeLoops, VertLoops)
fn getEdgeLoops polyMod edgeIds =
(
    -- 引数edgeIdsをbitarrayに変換する
    edgeIds = if isKindOf edgeIds bitarray then copy edgeIds 
        else edgeIds as bitarray

    -- 頂点ごとのエッジID、エッジごとの頂点IDをリスト化する
    local vertEdges = #()
    local edgeVerts = #()
    vertEdges.count = polyop.getNumVerts polyMod
    edgeVerts.count = polyop.getNumEdges polyMod
    for ei in edgeIds do
    (
        local v = polyop.getEdgeVerts polyMod ei
        edgeVerts[ei] = v
        local vEdges1 = vertEdges[v[1]]
        local vEdges2 = vertEdges[v[2]]
        if vEdges1 != undefined then append vEdges1 ei else vertEdges[v[1]] = #(ei)
        if vEdges2 != undefined then append vEdges2 ei else vertEdges[v[2]] = #(ei)
    )

    -- 現在のエッジから次のエッジを検索する
    fn _getNextEdge edges edgeIds =
    (
        local res = undefined
        for ei in edges while res == undefined do 
            if edgeIds[ei] do res = ei
        res
    )

    -- 現在の頂点から次の頂点を取得する
    fn _getNextVert verts lastVert =
    (
        if verts[1] == lastVert then
            verts[2]
        else
            verts[1]
    )

    -- エッジループを作成する
    local edgeLoops = #()
    local vertLoops = #()
    for ei in edgeIds do
    (
        edgeIds[ei] = false  -- Memo: ループ中にbitarrayの中身を変更すると、ループにも反映される
        local vertLoop = copy edgeVerts[ei] #noMap
        local edgeLoop = #(ei)

        -- 正方向へ検索
        local nextVert = vertLoop[2]
        local nextEdge = _getNextEdge vertEdges[nextVert] edgeIds
        while nextEdge != undefined do
        (
            nextVert = _getNextVert edgeVerts[nextEdge] nextVert
            append vertLoop nextVert
            append edgeLoop nextEdge

            edgeIds[nextEdge] = false
            nextEdge = _getNextEdge vertEdges[nextVert] edgeIds
        )

        -- 負方向へ検索
        local nextVert = vertLoop[1]
        local nextEdge = _getNextEdge vertEdges[nextVert] edgeIds
        while nextEdge != undefined do
        (
            nextVert = _getNextVert edgeVerts[nextEdge] nextVert
            insertItem nextVert vertLoop 1
            insertItem nextEdge edgeLoop 1

            edgeIds[nextEdge] = false
            nextEdge = _getNextEdge vertEdges[nextVert] edgeIds
        )
        append edgeLoops edgeLoop
        append vertLoops vertLoop
    )

    #(edgeLoops, vertLoops)
)

引数

polyObj
Editable_Polyベースオブジェクトまたはノード。
edgeIds
エッジIDを指定したbitarray。

戻り値

配列 #(edgeLoops, vertLoops)

edgeLoop
エッジID配列の配列。
vertLoops
頂点ID配列の配列。
edgeLoopとvertLoopsは同じサイズになり、頂点数はエッジ数+1になる。

 
ここで、各配列の外側の配列が左図の#1, #2, #3のようにグループを格納し、内側の配列は右図のようなエッジIDと頂点IDの配列になります。

この時、必ずエッジIDと頂点IDは対応するループ順になるように取得されます。

また、以下のようにエッジが交差する場合は、パターンAのようになるかBのようになるかはその時のトポロジ構造により、エッジIDの若い順にルートを決定しているので、ほぼランダムとなります。詳細にコントロールしたい場合はコードを修正して、エッジ角によって選択するルートを変更するような仕組みにする必要があります。

もう一点、#3のようにエッジがリング状にループしている場合、基点として使用されるのは頂点IDの最も若い頂点となります。
その場合、取得した頂点の始点と終点は同じIDになるので、それを調べればエッジループが循環している事を知る事が出来ます。

エッジIDをループ毎にグループ化する」への1件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。