« C.O.F.F.E.E.を使わず手作業で、月面の地形データを取り込んでみる… | トップページ | C4Dを使い込んでいない為に、標準搭載機能を気付かずXPressoで作成しようと…ネジネジ…C4DスイープNURBS »

C4D線形スプラインの角のポイント以外を選択するスクリプト

今回は、線形スプラインの角以外のポイントを選択します。
「角以外のポイント」を説明する必要は無いとは思いますが、

Corner_01

こんな感じです。

今回はセグメントに非対応ですが、複数スプラインに対応させます。

では、メニューの状態から。

ENABLE = (GetActiveObject(doc) != NULL);

これで、選択されたオブジェクトがあればメニュー表示は可視状態になります。
ただし、スプラインが含まれていなくても可視状態になります。
より厳密にメニューの状態を操作するなら、選択されたオブジェクトのクラスチェックが必要です。

ではスクリプトのメインです。

/*
線形スプラインの角以外のポイントを選択
2009.5.19
*/


main(doc , op)
{
  var obj = GetActiveObject(doc);
  if(!obj)return//選択されているオブジェクトが無ければ終了

  var i;    //ループカウンター
  var pts;  //スプラインのポイント
  var ptc;  //スプラインのポイント数
  var sel;  //ポイントの選択状況
  var nxt;  //対象の後ろのポイント
  var pre;  //対象の前のポイント
  var ang;  //対象の角度
  var liner = Radians(179.5);  //直線とみなす角度。

  while(obj){
    if(instanceof(obj , SplineObject)){  //スプラインオブジェクトのみ対象
      if(obj->GetSegmentCount() < 2 && obj#SPLINEOBJECT_TYPE == SPLINEOBJECT_TYPE_LINEAR){  //セグメントが2未満で線形スプラインのみ対象
        pts = obj->GetPoints();          //ポイント取得
        ptc = obj->GetPointCount();      //ポイント数の取得
        sel = obj->GetPointSelection();  //ポイント選択状況の取得

        sel->DeselectAll();  //全てのポイント選択を解除

        for(i = 0 ; i < ptc ; i++){  //スプラインオブジェクトのポイントの捜査
          if(i + 1 < ptc)nxt = pts[i + 1];else nxt = pts[0];  //対象の後ろのポイントの取得
          if(i - 1 >  -1)pre = pts[i - 1];else pre = pts[ptc - 1];  //対象の前のポイントの取得
          ang = acos(vnorm(pre - pts[i]) * vnorm(nxt - pts[i]));//対象の角度を算出。
          if(ang > liner)sel->Select(i);//直線ならば対象ポイントを選択
        }
        if(!obj#SPLINEOBJECT_CLOSED){//スプラインが閉じていなければ、最初と最後のポイントの選択を解除
          sel->Deselect(0);
          sel->Deselect(ptc - 1);
        }
        obj->SetPointSelection(sel);//選択状況の適用
      }
    }
    obj = obj->SearchNext(BIT_AOBJ);//次の選択されたオブジェクトの取得
  }
}

これで、線形スプラインの直線部のポイントが選択されます。

liner = Radians(179.5);

直線とみなす角度です。

ラジアン値だと、3.132866
この値で、直線180度のどれぐらいの制度か、直ぐにわかる人は凄いね。

180.0でも良いのですが、直線部を分割したにもかかわらず、選択されないポイントが出てくる可能性があります。これで調節します。
こうなるとダイアログが必要になりますね。

セグメントは対応していません。
実はセグメント数は…

以前、セグメントの数に触れたことがあります。
2個以上は、GetSegmentCount()が返す値そのままので、
1個以下は 0 と説明したと思います。
http://villager-and-c4d.cocolog-nifty.com/blog/2008/06/sendmodelingcom_4a61.html
たしか、1個の時はセグメントとみなさないのでは…と、

実は、そうではなかったのです。
一度セグメントを編集したスプラインは、セグメントを繋いで1個にしても、GetSegmentCount()が返す値は 0 にはなりません。1を返します。
ここで注意が必要です。
セグメントの無いスプラインだけを対象にするために、

if(!(obj->GetSegmentCount())){...}//セグメントが無い場合処理する

このようにすると、セグメント編集済みで1個になったスプラインが対象外になります。

次にスプラインタイプの話です。
これがスプラインタイプの定数です。

線形 SPLINEOBJECT_TYPE_LINEAR
3次 SPLINEOBJECT_TYPE_CUBIC
Akima SPLINEOBJECT_TYPE_AKIMA
Bスプライン SPLINEOBJECT_TYPE_BSPLINE
ベジエ SPLINEOBJECT_TYPE_BEZIER

スプラインタイプの判別で

if(obj#SPLINEOBJECT_TYPE == 0){...}//線形ならば処理

でも良いのですが、バージョンアップなどでC4Dの内部で順番が変わったりすると、思った通りのタイプの設定ではなくなる可能性があります。
可能性があると言うだけで、整合性を取りながらC4Dの開発を進めるだろうから、大丈夫だとは思います。
ま、バグ取り等でスクリプトを見返した時、定数を使った方が、どのタイプか直ぐにわかるので定数を使ったほうが良いかもね…1行が長くなりますけど…

と言いつつ、面倒なので0,1,2,3…って打っちゃいますけどね…

今回は、このぐらいだろうか…

ん、Undoが無い…
そう言えば最近、Undoを打った記憶がないなぁ…

では、Undoを追加して終了です。コメントはありません。

/*
線形スプラインの角以外のポイントを選択
2009.5.19
*/

main(doc , op)
{
  var obj = GetActiveObject(doc);
  if(!obj)return;

  var i;
  var pts;
  var ptc;
  var sel;
  var nxt;
  var pre;
  var ang;
  var liner = Radians(179.5);

  doc->StartUndo();//Undoの記録の開始

  while(obj){
    if(instanceof(obj , SplineObject)){
      if(obj->GetSegmentCount() < 2 && obj#SPLINEOBJECT_TYPE == SPLINEOBJECT_TYPE_LINEAR){

        doc->AddUndo(UNDO_OBJECT_BASEDATA , obj);//オブジェクトをUndoに追加

        pts = obj->GetPoints();
        ptc = obj->GetPointCount();
        sel = obj->GetPointSelection();

        sel->DeselectAll();

        for(i = 0 ; i < ptc ; i++){
          if(i + 1 < ptc)nxt = pts[i + 1];else nxt = pts[0];
          if(i - 1 >  -1)pre = pts[i - 1];else pre = pts[ptc - 1];
          ang = acos(vnorm(pre - pts[i]) * vnorm(nxt - pts[i]));
          if(ang > liner)sel->Select(i);
        }
        if(!obj#SPLINEOBJECT_CLOSED){
          sel->Deselect(0);
          sel->Deselect(ptc - 1);
        }
        obj->SetPointSelection(sel);
      }
    }
    obj = obj->SearchNext(BIT_AOBJ);
  }
  doc->EndUndo();//Undoの記録の終了
}

|

« C.O.F.F.E.E.を使わず手作業で、月面の地形データを取り込んでみる… | トップページ | C4Dを使い込んでいない為に、標準搭載機能を気付かずXPressoで作成しようと…ネジネジ…C4DスイープNURBS »