« C4D XPresso「値を記憶」ノードで遊んでみる。 | トップページ | どうでも良いようなプラグインを登録してしまった…「Bスプラインをベジェに変換」 »

C.O.F.F.E.E.で「指定したポリゴンの隣接ポリゴン」にアクセス

指定したポリゴンの隣接ポリゴンを取得するにはどうしたらよいのでしょう。
ポリゴンデータ配列内の検索。

隣接ポリゴンと言うのはどんなポリゴンだろう。
C.O.F.F.E.E.でポリゴンを扱った事のある人ならば、簡単に答えてくれるでしょう。
「エッジを共有している」もしくは「ポイントを共有している」ですね。

Polygonselection_01 Polygonselection_02

ただしC.O.F.F.E.E.はエッジをサポートしていないので「エッジの両端の2点を共有している」ということです。

どちらが簡単かと言うと、「ポイントを共有している」方が簡単なので、「ポイントを共有している」方で実験スクリプトを試してみます。

では、ポリゴンを1枚だけ選択して、次のユーザスクリプトを実行。

/*
ポイントを共有した隣接ポリゴンの選択
2009.1.31
*/

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

  var pgsel = op->GetPolygonSelection();//ポリゴン選択状況を取得
  var pgsel_c = pgsel->GetCount();//ポリゴン選択枚数の取得
  if(pgsel_c != 1)return;//今回は選択枚数が1枚以外は終了

  var i , j , k;//カウンター
  var pg_c = op->GetPolygonCount();//ポリゴン数の取得
  var pgs = op->GetPolygons();     //ポリゴンデータ配列の取得

  for(i = 0 ; i < pg_c ; i++) if(pgsel->IsSelected(i))break;//選択ポリゴン番号の取得

  var selpg = i;

  //選択ポリゴンのポイント4点の取得
  var pts = new(array , 4);//4点格納配列
  for(i = 0 ; i < 4 ; i++) pts[i] = pgs[selpg * 4 + i];//4点の格納

  //4点を共有するポリゴンを記録
  var sel = new(BaseSelect);//ポイントを共有するポリゴンを記録するためのBaseSelect
  for(i = 0 ; i < pg_c ; i++){ //ポリゴン数ループ
    for(j = 0 ; j < 4 ; j++){  //ポイント数4ループ
      for(k = 0 ; k < 4 ; k++){//選択されたポリゴンの格納したポイント数4ループ
        if(pgs[i * 4 + j] == pts[k])sel->Select(i);//オブジェクトのポイントと
      }                                            //格納したポイントを比較し

    }                                              //同じであればBaseSelectに記録(選択状態)
  }

  op->SetPolygonSelection(sel);//確認のため、記録したBaseSelectをオブジェクトに適用してみる

}

成功していれば、上の図の右側と同じ選択範囲になっています。

では次に、「エッジを共有している」方の実験スクリプト。
上とほぼ同じです。

/*
エッジを共有した隣接ポリゴンの選択
2009.1.31
*/

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

  var pgsel = op->GetPolygonSelection();//ポリゴン選択状況を取得
  var pgsel_c = pgsel->GetCount();//ポリゴン選択枚数の取得
  if(pgsel_c != 1)return;//今回は選択枚数が1枚以外は終了

  var i , j , k;//カウンター
  var pg_c = op->GetPolygonCount();//ポリゴン数の取得
  var pgs = op->GetPolygons();     //ポリゴンデータ配列の取得

  for(i = 0 ; i < pg_c ; i++) if(pgsel->IsSelected(i))break;//選択ポリゴン番号の取得

  var selpg = i;

  //選択ポリゴンのポイント4点の取得
  var pts = new(array , 4);//4点格納配列
  for(i = 0 ; i < 4 ; i++) pts[i] = pgs[selpg * 4 + i];//4点の格納


  //エッジを共有するポリゴンを記録
  var sel = new(BaseSelect);//ポイントを共有するポリゴンを記録するためのBaseSelect
  var ptn_1 , ptn_2 , ptn_3;//比較したポイントの隣のポイント
  for(i = 0 ; i < pg_c ; i++){ //ポリゴン数ループ
    for(j = 0 ; j < 4 ; j++){  //ポイント数4ループ
      for(k = 0 ; k < 4 ; k++){//選択されたポリゴンの格納したポイント数4ループ
        if(pgs[i * 4 + j] == pts[k]){
          ptn_1 = j + 1;if(ptn_1 > 3)ptn_1 = 0;//後ろのポイント番号の算出
          ptn_2 = k + 1;if(ptn_2 > 3)ptn_2 = 0;//後ろのポイント番号の算出
          ptn_3 = k - 1;if(ptn_3 < 0)ptn_3 = 3;//前のポイント番号の算出
          if(pgs[i * 4 + ptn_1] == pts[ptn_2] || pgs[i * 4 + ptn_1] == pts[ptn_3]) sel->Select(i);//条件を満たしていればBaseSelectに記録(選択状態)
        }
      }
    }
  }

  op->SetPolygonSelection(sel);//確認のため、記録したBaseSelectをオブジェクトに適用してみる

}

最初の同じポイントが取得できれば、その隣(+1)と相手の比較ポイントの隣(+1)または(-1)と比較して同じであればエッジを共有していることになる。※全てのポリゴンが時計回りで指定されているとは限りません。
比較ポイントの隣のポイントを取得するため+1した時、4になってしまったら0に、-1した時に-1になった時は3にしています。

Polygonselection_03

スクリプトを単純にするために、少し考え方をかえて、4点中2点が同じであれば、隣接としても可能であろう。

  //エッジを共有するポリゴンを記録
  var sel = new(BaseSelect);//ポイントを共有するポリゴンを記録するためのBaseSelect
  var pc;//同じポイントカウンター
  for(i = 0 ; i < pg_c ; i++){ //ポリゴン数ループ
    pc = 0;                    //同じポイントカウンターの初期化
    for(j = 0 ; j < 4 ; j++){  //ポイント数4ループ
      for(k = 0 ; k < 4 ; k++){//選択されたポリゴンの格納したポイント数4ループ
        if(pgs[i * 4 + j] == pts[k])pc++;//ポイントが同じであればカウント
      }
    }
    if(pc > 1) sel->Select(i);           //同じポイントが2個以上になればBaseSelectに記録(選択状態)
  }

ただし、このスクリプトは、少し問題があります。
比較するポリゴンが、対角線でポイントを共有している場合、選択されてしまいます。

Polygonselection_05

もうひとつ、三角ポリゴンの場合、3番目(2)のポイントを共有している場合、4番目(3)も3番目(2)と同じポイントを指しているので、見た目1点だけの共有のところ、2点共有していることになってしまいます。

Polygonselection_04

シンプルに出来ると思われたこの考え方も、これらの2つの不具合に対処する為にスクリプトを追加する必要が出てきました。

|

« C4D XPresso「値を記憶」ノードで遊んでみる。 | トップページ | どうでも良いようなプラグインを登録してしまった…「Bスプラインをベジェに変換」 »

コメント

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