« C4D BasePointのGetPoint()/SetPoint()の簡単なスピードテスト | トップページ | インストールしたC4DやインストールされたPCの情報の取得 »

前回の新規ヌルオブジェクトをポイントやポリゴンに追加配置するユーザスクリプトに「オブジェクトモード」を追加する

前回の「新規ヌルオブジェクトをポイントやポリゴンに追加配置するユーザスクリプト」
http://villager-and-c4d.cocolog-nifty.com/blog/2009/05/post-c749.html
に「オブジェクトモード」を追加します。

それでは、オブジェクトモード」の時、選択したオブジェクトの何処にヌルオブジェクトを配置しますか?

オブジェクトモードだから…

ポイントとポリゴンの両方に配置するのか?
オブジェクトの軸に配置するのか?(既にヌルオブジェクトをまとめる"group"です。)
それともオブジェクトの中心?
それとも全ポイントの総和の平均?

個人的には、全ポイントの総和の平均が良いと思うのですが…
そもそも「オブジェクトモード」で移動、回転、スケールは軸基準なので、軸に配置する事にします。

そうすると、既にヌルオブジェクトをまとめる"group"が、それなのです。

そうすると…

スクリプトコードの変更は、あっさり終わります。

/*
ポイントやポリゴンにヌルオブジェクトを追加配置する。
2009.5.26
*/



main(doc , op)
{

  var obj = GetActiveObject(doc);
 
if(!obj)return;

 
var mode = 0;
 
var cs;
 
var name;

 
var gp;
 
var nulobj;
 
var pts , pgs;
 
var lpc;
 
var sel;
 
var pos;
 
var i;

 
if(IsCommandChecked(12139)){
    mode = 1;
//ポイントモードだと:1
    cs =
PointObject;
    name =
"point_";
  }
 
if(IsCommandChecked(12187)){
    mode = 2;
//ポリゴンモードだと:2
    cs = PolygonObject;
    name =
"polygon_";
  }
  if(IsCommandChecked(12101)){
    mode = 3;//オブジェクトモードだと:3
    cs = BaseObject;
  }


 
if(!mode)return;

  doc->
StartUndo();

 
while(obj){
   
if(instanceof(obj , cs)){
      doc->
AddUndo(UNDO_OBJECT_REC , obj);

      
//グループオブジェクトの追加
      gp =
new(NullObject);
      gp->
SetName("group");
      gp->
InsertUnder(obj);

      if(mode != 3){

       pts = obj->
GetPoints();

       
switch(mode){
         
case 1:
            lpc = obj->
GetPointCount();
            sel = obj->
GetPointSelection();
            
break;
         
case 2:
            lpc = obj->
GetPolygonCount();
            pgs = obj->
GetPolygons();
            sel = obj->
GetPolygonSelection();
        }
       
for(i = 0 ; i < lpc ; i++){
         
if(sel->IsSelected(i) || !(sel->GetCount())){

            //ヌルオブジェクトの追加
            nulobj =
new(NullObject);
            nulobj->
InsertUnder(gp);
            nulobj->
SetName(name + tostring(i));
            nulobj#
NULLOBJECT_DISPLAY = 2;

            
//ヌルオブジェクトの位置の調整と適用
            
switch(mode){
             
case 1:
                pos = pts[i];
               
break;
            
case 2:
                if(pgs[i * 4 + 2] != pgs[i * 4 + 3]){
                  pos = (pts[pgs[i * 4]] +
                         pts[pgs[i * 4 + 1]] +
                         pts[pgs[i * 4 + 2]] +
                         pts[pgs[i * 4 + 3]]) / 4;
                }
else{
                  pos = (pts[pgs[i * 4]] +
                         pts[pgs[i * 4 + 1]] +
                         pts[pgs[i * 4 + 2]]) / 3;
                }

            }

            nulobj->SetPosition(pos);
          }
        }
      }
    }
    obj = obj->
SearchNext(BIT_AOBJ);
  }
  doc->
EndUndo();
}

これで、スクリプトは問題なく動きます。

オブジェクトモードの時は、オブジェクトの軸に配置します。
選択された全てのオブジェクトが対象になるように、instanceof()で比較するクラスはBaseObjectです。

このスクリプトの最後の部分のブロックの最後を示す括弧「 } 」が多すぎで、どのブロックの括弧か直ぐに分からないですよね。

               :
               :
            nulobj->SetPosition(pos);

          }//if(sel->IsSelected(i) || !sel->GetCount())

        }//for()

      }//if(mode != 3)

    }//if(instanceof())

    obj = obj->SearchNext(BIT_AOBJ);

  }
//while()

  doc->
EndUndo();
}

この様なブロックですね。
「閉じ括弧にコメントを入れよう!」ではなくて…

ブロックそのものを削除するか、広域にしない様にしたらどうだろう。
例えば次のようにして、obj = obj->SearchNext(BIT_AOBJ);の前のif(instanseof())の括弧を削除します。

単純なif(){}なので、条件式の結果を反転しcontinueを使用するとwhile()のブロックの最後にジャンプできます。
ただし重要なobj = obj->SearchNext(BIT_AOBJ)が実行されないので、continueの前に実行します。

    :
    :

  while(obj){
    if(!instanceof(obj , cs)){
      obj = obj->SearchNext(BIT_AOBJ);
      continue;
    }
    doc->AddUndo(UNDO_OBJECT_REC , obj);

      :
      :

同様にしてif(mode != 3)の括弧も消すことができますね。

        :
        :

      if(mode == 3){
        obj = obj->SearchNext(BIT_AOBJ);
       
continue;
      }

        :
        :

今回のif(instanceof())もif(mode != 3)も条件式がFALSEの時while()ブロックの最後のobj = obj->SearchNext(BIT_AOBJ)を実行してwhile()の1回分の繰り返しを終わるので、上のようなコードになります。
全てがこのようになるわけではありません。

さらに同様にして、if(sel->IsSelected(i) || !sel->GetCount())の括弧も削除できます。

…ところで、最近取り上げたfor()の記事を覚えているだろうか…
http://villager-and-c4d.cocolog-nifty.com/blog/2009/05/c4dcoffeefor-2c.html

ここで使用している

while(obj){
    :
  obj = obj->SearchNext(BIT_AOBJ);
}

をfor()に置き換えます。

for(obj = GetActiveObject(doc) ; obj ; obj = obj->SearchNext(BIT_AOBJ)){

}

上のようにwhile()をfor()に置き換えると、先ほどのif(instanceof())もif(mode != 3)も次のようにできます。

for(obj = GetActiveObject(doc) ; obj ; obj = obj->SearchNext(BIT_AOBJ)){
  if(!instanceof(obj , cs))continue;
    :
  if(mode == 3)continue;
    :
}

for()なのでループ内でcontinueを実行しても、obj = obj->SearchNext(BIT_AOBJ)が必ず実行されます。

では、ここで一旦修正したスクリプトを見てみましょう。
と、言っても見た目劇的に変わるわけではないですけどね…

/*
ポイントやポリゴンにヌルオブジェクトを追加配置する。
2009.5.26
*/



main(doc , op)
{

  var obj = GetActiveObject(doc);
 
if(!obj)return;

 
var mode = 0;
 
var cs;
 
var name;

 
var gp;
 
var nulobj;
 
var pts , pgs;
 
var lpc;
 
var sel;
 
var pos;
 
var i;

 
if(IsCommandChecked(12139)){
    mode = 1;
//ポイントモードだと:1
    cs =
PointObject;
    name =
"point_";
  }
 
if(IsCommandChecked(12187)){
    mode = 2;
//ポリゴンモードだと:2
    cs = PolygonObject;
    name =
"polygon_";
  }
 
if(IsCommandChecked(12101)){
    mode = 3;
//オブジェクトモードだと:3
    cs =
BaseObject;
  }
 
if(!mode)return;


  doc->
StartUndo();

  for(obj = GetActiveObject(doc) ; obj ; obj = obj->SearchNext(BIT_AOBJ)){
    if(!instanceof(obj , cs))continue;

    doc->
AddUndo(UNDO_OBJECT_REC , obj);

   
//グループオブジェクトの追加
    gp =
new(NullObject);
    gp->
SetName("group");
    gp->
InsertUnder(obj);

    if(mode == 3)continue;

    pts = obj->
GetPoints();

   
switch(mode){
      
case 1:
        lpc = obj->
GetPointCount();
        sel = obj->
GetPointSelection();
       
break;
      
case 2:
        lpc = obj->
GetPolygonCount();
        pgs = obj->
GetPolygons();
        sel = obj->
GetPolygonSelection();
    }
   
for(i = 0 ; i < lpc ; i++){
      
if(sel->IsSelected(i) || !(sel->GetCount())){
        //ヌルオブジェクトの追加
        nulobj =
new(NullObject);
        nulobj->
InsertUnder(gp);
        nulobj->
SetName(name + tostring(i));
        nulobj#
NULLOBJECT_DISPLAY = 2;

       
//ヌルオブジェクトの位置の調整と適用
       
switch(mode){
         
case 1:
            pos = pts[i];
            
break;
         
case 2:
            if(pgs[i * 4 + 2] != pgs[i * 4 + 3]){
              pos = (pts[pgs[i * 4]] +
                     pts[pgs[i * 4 + 1]] +
                     pts[pgs[i * 4 + 2]] +
                     pts[pgs[i * 4 + 3]]) / 4;
            }
else{
              pos = (pts[pgs[i * 4]] +
                     pts[pgs[i * 4 + 1]] +
                     pts[pgs[i * 4 + 2]]) / 3;
            }

        }

        nulobj->SetPosition(pos);
      }
    }

  }
  doc->
EndUndo();
}

問題なく動作する事でしょう。

では、もう一箇所if(sel->IsSelected(i) || !sel->GetCount())の括弧を削除してみよう。

この条件式の反対は…エレメントが選択されているか、それとも全く選択されていない…

難しく考えないで単純に全体を括弧で括って反転してみよう。

      if(!(sel->IsSelected(i) || !(sel->GetCount())))continue;

これで問題なしと…

でも、気になるなぁ

この条件式の反転を考えるのではなくて、処理から除外される条件を新たに考えれば良いのか…

選択されていないポイントで、選択されている数が0ではない。って事は…

      if(!(sel->IsSelected(i)) && sel->GetCount())continue;

これで良いのか?

問題ないね。

では最後に、完成したスクリプトです。

/*
ポイントやポリゴンにヌルオブジェクトを追加配置する。
2009.5.26
*/



main(doc , op)
{

  var obj = GetActiveObject(doc);
 
if(!obj)return;

 
var mode = 0;
 
var cs;
 
var name;

 
var gp;
 
var nulobj;
 
var pts , pgs;
 
var lpc;
 
var sel;
 
var pos;
 
var i;

 
if(IsCommandChecked(12139)){
    mode = 1;
//ポイントモードだと:1
    cs =
PointObject;
    name =
"point_";
  }
 
if(IsCommandChecked(12187)){
    mode = 2;
//ポリゴンモードだと:2
    cs = PolygonObject;
    name =
"polygon_";
  }
 
if(IsCommandChecked(12101)){
    mode = 3;
//オブジェクトモードだと:3
    cs =
BaseObject;
  }
 
if(!mode)return;


  doc->
StartUndo();

 
for(obj = GetActiveObject(doc) ; obj ; obj = obj->SearchNext(BIT_AOBJ)){
   
if(!instanceof(obj , cs))continue;

    doc->
AddUndo(UNDO_OBJECT_REC , obj);

   
//グループオブジェクトの追加
    gp =
new(NullObject);
    gp->
SetName("group");
    gp->
InsertUnder(obj);

   
if(mode == 3)continue;

    pts = obj->
GetPoints();

   
switch(mode){
      
case 1:
        lpc = obj->
GetPointCount();
        sel = obj->
GetPointSelection();
       
break;
      
case 2:
        lpc = obj->
GetPolygonCount();
        pgs = obj->
GetPolygons();
        sel = obj->
GetPolygonSelection();
    }
   
for(i = 0 ; i < lpc ; i++){
      if(!(sel->IsSelected(i)) && sel->GetCount())continue;
      //ヌルオブジェクトの追加
      nulobj =
new(NullObject);
      nulobj->
InsertUnder(gp);
      nulobj->
SetName(name + tostring(i));
      nulobj#
NULLOBJECT_DISPLAY = 2;

      
//ヌルオブジェクトの位置の調整と適用
      
switch(mode){
       
case 1:
          pos = pts[i];
         
break;
       
case 2:
          if(pgs[i * 4 + 2] != pgs[i * 4 + 3]){
            pos = (pts[pgs[i * 4]] +
                   pts[pgs[i * 4 + 1]] +
                   pts[pgs[i * 4 + 2]] +
                   pts[pgs[i * 4 + 3]]) / 4;
          }
else{
            pos = (pts[pgs[i * 4]] +
                   pts[pgs[i * 4 + 1]] +
                   pts[pgs[i * 4 + 2]]) / 3;
          }

      }

      nulobj->SetPosition(pos);
    }

  }
  doc->
EndUndo();
}

このようになると、「ポイントやポリゴンにヌルオブジェクトを配置する」ではなくて、「オブジェクトにヌルオブジェクトを配置する」と名前を変えたほうが良いかもね。

|

« C4D BasePointのGetPoint()/SetPoint()の簡単なスピードテスト | トップページ | インストールしたC4DやインストールされたPCの情報の取得 »