Help us understand the problem. What is going on with this article?

[Cinema 4D] スプラインのバウンディングボックスを作成してみる

More than 1 year has passed since last update.

前回の記事でポリゴンオブジェクトからワールド座標に平行なバウンディングボックスを作成することができましたが,今回は前回のスクリプトを少し拡張してCinema 4Dでよく使うスプラインオブジェクトからバウンディングボックスを作成してみようと思います.

スプラインはポリゴンオブジェクトとは異なるタイプのオブジェクトなので,if文で条件分岐させてあげますが,少し注意が必要です.

例えば,ポリゴンオブジェクトの場合はobj.IsInstanceOf(c4d.Opolygon)などでタイプをチェックできます.

InstanceOfのマニュアル

これでIsInstanceOf(c4d.Ospline)でスプラインタイプがチェックできるかと思いきやこれはできません.

スプラインタイプの場合は,次のようにしてあげます.他にGetType() == c4d.Osplineでもできます.InstanceOfだとできないんですね.

if obj.GetInfo() & c4d.OBJECT_ISSPLINE:
    realSpline = obj.GetRealSpline()
    if realSpline is False:
        return
    # Do something

2行目のGetRealSpline()でプリミティブスプラインから編集可能にした状態のスプラインを取得します.

GetRealSpline()

これで準備ができたので,あとはポリゴンオブジェクトと同様にrealSpline.GetClone()でクローンを取得してそれに対して逆行列をかけてワールド座標に平行にしたのち,各ポイントに回転行列を乗算して元の位置にもどしてあげます.前回と全く同じ手順です.

できました
20190303-1.jpg

と言いたいところですが,接線の端までバウンディングボックスができてしまっています.これはちょっとよくないですね.どうやらGetRad()は接線の端まで含んだ半径を返すようです.

そこで,このクローンスプラインに対して〈現在の状態をオブジェクト化〉をして内部で生成している実際のポイントを取得していきます.英語ではCurrent State to Objectです.Plugincafeでもこのトピックは沢山みつかるので,検索してみると良いでしょう.

オブジェクトに対してutils.SendModelingCommandを実行するわけですが,先にモジュールをインポートしておきます.

from c4d import utils
rs = obj.GetRealSpline()
if rs is False:
    return

clone = rs.GetClone()
clone.SetMg(~obj.GetMg() * obj.GetMg())
settings = c4d.BaseContainer()
res = utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                                list = [clone],
                                mode = c4d.MODELINGCOMMANDMODE_ALL,
                                bc = settings,
                                doc = doc)
c4d.EventAdd()

if res is False:
    print "Something went wrong."
elif res is True:
    print "Command successful."
elif isinstance(res, list):
    print "Here you get the newly created object(s)."

[utils.SendModelingCommand]のマニュアル(https://developers.maxon.net/docs/Cinema4DPythonSDK/html/modules/c4d.utils/index.html?highlight=sendmodelingcommand#c4d.utils.SendModelingCommand)

commandは実行するコマンドです.
引数のオブジェクトはリストになっているので,[clone]としています.
modeはALLのほか,選択範囲に限定したりできます.
settingsは実行コマンドのパラメータを指定できます.例えばID_MODELING_EXTRUDE_TOOLを使う場合に50cm押し出したい時などです.〈現在の状態をオブジェクト化〉では不要ですが.

注意点としては,複製したオブジェクトを渡さないとシーン内のスプラインに対してコマンドが実行されてしまいます.したがって,この時[clone]を渡しています.

また,返り値はリストになるので,実行後のオブジェクトへはres[0].GetPointCount()などとしてアクセスします.

関数は次のようにしてみました.引数のobjはすでに記事冒頭のobj.GetInfo() & c4d.OBJECT_ISSPLINE:でスプラインオブジェクトだけを渡すようにしていますので,関数内でスプラインかどうかのチェックはしていません.

def createBoundingBoxFromSpline(obj):
    print "Call createBoundingBox from Spline"

    # もしスプラインプリミティブならスプライン状態を取得する(編集可能にした状態)
    rs    = obj.GetRealSpline()
    if rs is False:
        return

    # クローンをとる
    clone = rs.GetClone()
    clone.SetMg(~obj.GetMg() * obj.GetMg())

    # 現在の状態をオブジェクト化
    settings = c4d.BaseContainer()
    res = utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                                    list = [clone],
                                    mode = c4d.MODELINGCOMMANDMODE_ALL,
                                    bc = settings,
                                    doc = doc)
    c4d.EventAdd()

    if res is False:
        print "Something went wrong."
    elif res is True:
        print "Command successful."
    elif isinstance(res, list):
        print "Here you get the newly created object(s)."

    # ポイントに元の行列を乗算してポイントだけ元の位置に戻す
    if res[0].GetPointCount():
        pcount = res[0].GetPointCount()
        points = res[0].GetAllPoints()
        for p in xrange(pcount):
            res[0].SetPoint(p, obj.GetMg() * points[p])
            print points[p]
        res[0].Message(c4d.MSG_UPDATE)
        c4d.EventAdd()

    # XYZの最小,最大値を取得する
    center = res[0].GetMp()
    xMin = center.x + res[0].GetRad().x * -1
    xMax = center.x + res[0].GetRad().x
    yMin = center.y + res[0].GetRad().y * -1
    yMax = center.y + res[0].GetRad().y
    zMin = center.z + res[0].GetRad().z * -1
    zMax = center.z + res[0].GetRad().z
    print xMin
    print xMax
    print yMin
    print yMax
    print zMin
    print zMax

    # XYZの最小・最大値からバウンディングボックスを生成する
    box = c4d.BaseObject(c4d.Opolygon)
    box.ResizeObject(8,6)
    box.SetPoint(0,c4d.Vector(xMin, yMin, zMin))
    box.SetPoint(1,c4d.Vector(xMin, yMax, zMin))
    box.SetPoint(2,c4d.Vector(xMax, yMin, zMin))
    box.SetPoint(3,c4d.Vector(xMax, yMax, zMin))
    box.SetPoint(4,c4d.Vector(xMax, yMin, zMax))
    box.SetPoint(5,c4d.Vector(xMax, yMax, zMax))
    box.SetPoint(6,c4d.Vector(xMin, yMin, zMax))
    box.SetPoint(7,c4d.Vector(xMin, yMax, zMax))
    box.SetPolygon(0, c4d.CPolygon(0,1,3,2))
    box.SetPolygon(1, c4d.CPolygon(2,3,5,4))
    box.SetPolygon(2, c4d.CPolygon(4,5,7,6))
    box.SetPolygon(3, c4d.CPolygon(6,7,1,0))
    box.SetPolygon(4, c4d.CPolygon(1,7,5,3))
    box.SetPolygon(5, c4d.CPolygon(6,0,2,4))
    doc.InsertObject(box)

    tag = c4d.BaseTag(c4d.Tdisplay)
    tag[c4d.DISPLAYTAG_AFFECT_DISPLAYMODE] = True
    tag[c4d.DISPLAYTAG_SDISPLAYMODE] = 6
    tag[c4d.DISPLAYTAG_WDISPLAYMODE] = 0
    box.InsertTag(tag)

    box.Message(c4d.MSG_UPDATE)
    doc.AddUndo(c4d.UNDOTYPE_NEW,box)
    doc.EndUndo()
    c4d.EventAdd()
    return

できました
20190303-2.jpg

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした