« C.O.F.F.E.E.でポリゴンオブジェクトのポリゴン | トップページ | C.O.F.F.E.E.でUVWタグにアクセス-1.準備 »

C.O.F.F.E.E.でポリゴンオブジェクトの選択されたポリゴンを変形

前回、ポリゴンオブジェクトからポリゴンを取得し、対応したポイント番号を得ることができました。では次は、ポイントオブジェクトの時と同じく選択されたポリゴンを取得し、対応したポイント番号を更に取得し、そのポイントを変更してオブジェクトに適用すれば、ポリゴンを変形させることができるわけですね。ただし選択されたポリゴン毎にポイントを変更すると、隣り合ったポリゴンの場合はポイントを共有しているので、共有しているポリゴンの枚数分だけ変更されてしまいます。駄目なスクリプトは次の通りです。

/*
選択されたポリゴンの大きさを0.5倍にする
2008.12.24
*/


if(!instanceof(op , PolygonObject))return;//ポリゴンオブジェクト以外は終了

var pg = op->GetPolygons();//ポリゴン配列を取得
var pc = op->GetPolygonCount();//ポリゴン数を取得
var pt = op->GetPoints();//ポイントの取得
var pg_bs = op->GetPolygonSelection();//ポリゴンの選択状況の取得
var sc = 0.5;//倍率
var i;//カウンター
var im;//ポリゴン配列用マッピング

for(i = 0 ; i < pc ; i++){
  if(pg_bs->IsSelected(i)){//選択されたポリゴンならば
    im = i * 4;
    pt[pg[im    ]] = pt[pg[im    ]] * sc;//aのポイント座標を0.5倍
    pt[pg[im + 1]] = pt[pg[im + 1]] * sc;//bのポイント座標を0.5倍
    pt[pg[im + 2]] = pt[pg[im + 2]] * sc;//cのポイント座標を0.5倍
    pt[pg[im + 3]] = pt[pg[im + 3]] * sc;//dのポイント座標を0.5倍
  }
}

op->SetPoints(pt);//ポイントの適用
op->Message(MSG_UPDATE);//オブジェクトの更新

このスクリプトはオブジェクトのポリゴン配列、ポリゴン数、ポイント配列、ポリゴンの選択状況を取得し、ポリゴン選択状況を捜査し選択ポリゴンだと、ポリゴン配列からポイント番号を取得し、それをポイント配列のインデックスとしてポイントの座標を得る。その得た座標を0.5倍してポイント配列に代入する。ポリゴン選択状況を捜査後、ポイントをオブジェクトに適用して更新する。
これを実行すると選択されたポリゴンを変形することができますが、選択ポリゴン毎の処理なので共有しているポイントは複数回0.5倍されます。

では、どうするか?ポリゴン毎の処理をポイント毎の処理にするわけですね。具体的にどうするか?
選択されたポリゴンで使用されているポイント番号の配列を用意。
配列の大きさは、選択枚数×4
ポリゴンの選択状況を捜査し選択されたポリゴンのポイント番号を用意した配列に記録。ただし、記録するときは用意した配列を捜査し同じポイント番号があれば記録しない。
ポリゴン選択状況の捜査が終わったら、先ほど記録したポイント番号を元にポイントを処理。
オブジェクトにポイントを適用して更新。

/*
選択されたポリゴンの大きさを0.5倍にする。ポイント毎の処理。
2008.12.24
*/


if(!instanceof(op , PolygonObject))return;//ポリゴンオブジェクト以外は終了

var pg = op->GetPolygons();//ポリゴン配列を取得
var pc = op->GetPolygonCount();//ポリゴン数を取得
var pt = op->GetPoints();//ポイントの取得
var pg_bs = op->GetPolygonSelection();//ポリゴンの選択状況の取得
var sc = 0.5;//倍率
var i , j , k , c;//カウンター
var f;//フラグ
var
im;//ポリゴン配列用マッピング

//選択されたポリゴンのポイント数を得る
c = 0;
for(i = 0 ; i < pc ; i++){
  if(pg_bs->IsSelected(i))c++;
}


//処理ポイント番号用の配列の宣言と初期化
var def_pt = new(array , c * 4);//処理ポイント番号用
for(i = 0 ; i < c * 4 ; i++){//配列の初期化
  def_pt[i] = -1;//-1で初期化(ポイント番号が0からなので)
}


//処理ポイント番号のリストアップとダブりの処理
for(i = 0 ; i < pc ; i++){
  if(pg_bs->IsSelected(i)){//選択されたポリゴンならば
    im = i * 4;
    for(j = 0 ; j < 4 ; j++){
      f = 1;//配列内に同じ番号の有無のフラグ
      k = 0;//記録用配列のインデックスを先頭に
      while(def_pt[k] != -1){//配列内容が-1でなければループ
        if(def_pt[k] == pg[im + j])f = 0;//同じ番号があればフラグを下げる
        k++;
      }
      if(f)def_pt[k] = pg[im + j];//同じ番号が無ければポイント番号を記録
    }
  }
}

//リストアップしたポイント番号のポイント座標を0.5倍にする
for(i = 0 ; i < c*4 ; i++){
  if(def_pt[i] != -1)//リストの内容が-1でなければ
    pt[def_pt[i]] = pt[def_pt[i]] * sc;//ポイント座標を0.5倍
  else
    break;//-1ならばループを終了
}

op->SetPoints(pt);//ポイントの適用
op->Message(MSG_UPDATE);//オブジェクトの更新

適当に作ってみましたが、問題なく動いています。でも処理するポイント番号をリストアップするより、ポイント選択状況のBaseSelectのようにポイントに対応したビット配列を用意して処理するポイントにフラグを立てる方が単純だね。C.O.F.F.E.E.SDKのBaseSelectクラスに、自前で配列を用意するとメモリーを大量に消費する可能性があるけど、BaseSelectクラスを使うと、C4Dは配列を圧縮してメモリーの節約をするそうです。圧縮してるけど処理は速いらしい。
BaseSelectクラスを使ってみよう。
new(BaseSelect)で新規で取得する?
それともGetPointSelection()で取得する?
BaseSelectクラスにはInit()が有るけどアロケートされたとき初期化はされないのか?
Init()はどんなときに使うんだろう?全ての選択を解除するのか?それならDeselectAll()があるんだが?詳しい事は何も書いていない…考えるの面倒だからGetPointSelection()でBaseSelectを取得してDeselectAll()するかな?
BaseSelectのテストをしてみる。これは純粋なBaseSelectクラスのテストなのでオブジェクトは関係ありません。

/*
BaseSelectのテスト
2008.12.24
*/


var i;
var bs = new(BaseSelect);
println("宣言したばかりのGetCount() " , bs->GetCount());
for(i = 0 ; i < 101 ; i++)print(bs->IsSelected(i));
println("");

bs->Select(10);
println("適当に10番を選択状態にした時のGetCount() " , bs->GetCount());
for(i = 0 ; i < 101 ; i++)print(bs->IsSelected(i));
println("");

bs->DeselectAll();
println("全てを選択解除したときのGetCount() " , bs->GetCount());
for(i = 0 ; i < 101 ; i++)print(bs->IsSelected(i));
println("");

bs->SelectAll(0 , 100);
println("0から100を選択状態にしたGetCount() " , bs->GetCount());
for(i = 0 ; i < 101 ; i++)print(bs->IsSelected(i));
println("");

bs->SelectAll(20 , 30);
println("20から30を選択状態にしたGetCount() " , bs->GetCount());
for(i = 0 ; i < 101 ; i++)print(bs->IsSelected(i));
println("");

bs->Init();
println("Init()直後のGetCount() " , bs->GetCount());
for(i = 0 ; i < 101 ; i++)print(bs->IsSelected(i));
println("");

実行した結果は

宣言したばかりの要素数 0
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
適当に10番を選択状態にした時の要素数 1
00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
全てを選択解除したときの要素数 0
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0から100を選択状態にした要素数 101
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
20から30を選択状態にした要素数 11
00000000000000000000111111111110000000000000000000000000000000000000000000000000000000000000000000000
Init()直後の要素数 0
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

BaseSelectクラスのGetCount()は選択状態の数を返すんだね。
SelectAll()は指定した範囲を選択状態に、それ以外を選択解除なんだね。自分は勘違いしてました。指定した範囲を選択状態にするだけでそれ以外は変化無しだと思ってました。でもInit()とDeselectAll()の違いは全くわかりません。
それでもスクリプトは組めるでしょう…
ではポリゴンに戻りましょう。BaseSelectを使用した場合

/*
選択されたポリゴンの大きさを0.5倍にする。BaseSelectを使用。
2008.12.24
*/


if(!instanceof(op , PolygonObject))return;//ポリゴンオブジェクト以外は終了

var pg = op->GetPolygons();//ポリゴン配列を取得
var pg_c = op->GetPolygonCount();//ポリゴン数を取得
var pt = op->GetPoints();//ポイントの取得
var pt_c = op->GetPointCount();//ポイント数の取得
var
pg_bs = op->GetPolygonSelection();//ポリゴンの選択状況の取得
var bs = new(BaseSelect);//処理ポイント用
var sc = 0.5;//倍率
var
i , j;//カウンター

var
im;//ポリゴン配列用マッピング


//BaseSelectでポリゴンに対応したポイントにフラグを立て(選択状態)ます。
for(i = 0 ; i < pg_c ; i++){
  if(pg_bs->IsSelected(i)){//選択されたポリゴンならば
    im = i * 4;
    for(j = 0 ; j < 4 ; j++){//ポリゴンの4つのポイントをBaseSelectで選択状態に
      bs->Select(pg[im + j]);
    }
  }
}


//BaseSelectでフラグの立った(選択状態)ポイント座標を0.5倍にする
for(i = 0 ; i < pt_c ; i++){
  if(bs->IsSelected(i))//BaseSelectが選択状態ならば
    pt[i] = pt[i] * sc;//ポイント座標を0.5倍
}


op->SetPoints(pt);//ポイントの適用
op->Message(MSG_UPDATE);//オブジェクトの更新

先ほどの番号のリストアップと同じようにオブジェクトは変形します。
ただしBaseSelectを使ったほうが簡単にスクリプトが組めました。

|

« C.O.F.F.E.E.でポリゴンオブジェクトのポリゴン | トップページ | C.O.F.F.E.E.でUVWタグにアクセス-1.準備 »

コメント

この記事へのコメントは終了しました。