« C4D C.O.F.F.E.E.SendModelingCommand()「始点の設定」 | トップページ | C4D C.O.F.F.E.E. スプラインのポイント間の長さが取得できるようになったので、ベジェスプラインに勾配を付けてみる。 »

C4D C.O.F.F.E.E. 前回作成したスプラインのポイント間の長さを取得する関数の修正。

前回作成した、スプラインのポイント間の長さを取得する関数を修正します。

この関数は…
セグメントが無い、開いたBスプライン以外のスプラインが対象でした。
今回は、スプラインの開閉に対応します。

簡単な流れは…

  1. 開いているスプラインの終点を指定した場合は、長さ0.0を返して処理を終了します。
  2. ベジェに変換
  3. 指定したポイントを選択し始点に変更します。
  4. 始点の次のポイントを選択します。
  5. 選択を反転して、ポイントを削除します。
  6. スプラインが閉じていれば、開きます。
  7. 長さを取得します。
  8. 長さを返します。

こんな具合にします。

では、テストスクリプトです。

関数の動作確認をするので、実際にスプラインが加工され、指定したポイントと次のポイント以外が削除されます。

/*
スプラインのポイント間の長さを求めるテスト
2009.6.25
*/


//スプラインのポイント間の長さを取得
GetBetweenLength(dummy , number)
{
  if(!instanceof(dummy , SplineObject))return;//スプライン以外を排除
  if(dummy#SPLINEOBJECT_TYPE == SPLINEOBJECT_TYPE_BSPLINE)return;//Bスプラインを排除
  if(dummy->GetSegmentCount() >= 2)return;    //複数のセグメントを持つスプラインを排除

  var ptc = dummy->GetPointCount();
  if(number < 0 || number > ptc - 1)return;    //既存以外のポイント番号の指定を排除

  //開いているスプラインの場合で終点を指定した場合は、長さ0.0を返す
  if(number > ptc - 2 && !dummy#SPLINEOBJECT_CLOSED)return 0.0;

  var ct = new(BaseContainer);


  //ベジェに変更。線形の場合は変更後ハード補間
  var liner = FALSE;

  if(dummy#SPLINEOBJECT_TYPE == SPLINEOBJECT_TYPE_LINEAR)liner = TRUE;

  dummy#SPLINEOBJECT_TYPE = SPLINEOBJECT_TYPE_BEZIER;
  if(liner)SendModelingCommand(MCOMMAND_SPLINE_HARDINTERPOLATION , NULL , dummy , ct , MODIFY_ALL);


  //指定したポイントを選択
  var sel = new(BaseSelect);
  sel->Select(number);          //指定したポイントを選択状態にします。
  dummy->SetPointSelection(sel);//ポイント選択をオブジェクトに適用します。
  //始点の設定
  SendModelingCommand(MCOMMAND_SPLINE_REORDER , NULL , dummy , ct , MODIFY_POINTSELECTION);


  //次のポイントを選択
  sel = dummy->GetPointSelection();//始点の移動後のポイント選択状況の再取得
  sel->Select(1);                  //始点の次のポイントを選択
  dummy->SetPointSelection(sel);   //選択状況をオブジェクトに適用


  //選択の反転
  SendModelingCommand(MCOMMAND_SELECTINVERSE , NULL , dummy , ct , MODIFY_POINTSELECTION);


  //ポイントの削除
  SendModelingCommand(MCOMMAND_DELETE , NULL , dummy , ct , MODIFY_POINTSELECTION);


  //スプラインが閉じていれば開きます。
  if(dummy#SPLINEOBJECT_CLOSED)dummy#SPLINEOBJECT_CLOSED = FALSE;


  //長さの取得し返す
  dummy->InitLength(0);

  return dummy->GetLength();
}



main(doc , op)
{
  if(!instanceof(op , SplineObject))return;

  doc->StartUndo();
  doc->AddUndo(UNDO_OBJECT_BASEDATA , op);
  doc->EndUndo();

  println(GetBetweenLength(op , 6));
}

では、ポイントが7個のスプラインを用意してください。

Length_11

上のスクリプトは、終点の6番目と次のポイント間の長さを求めます。
開いていれば、0.0がコンソールに表示されます。

Length_13

0.000000

閉じていれば、スプラインが加工され、その長さが表示されます。

Length_12

143.044464

ポイント番号の範囲外や、Bスプライン、複数セグメントの場合は、nilが返ります。

問題なく動作していることを確認しました。

では、前回のように加工されないように、渡されたスプラインの複製で作業するように変更します。

/*
スプラインのポイント間の長さを求めるテスト2
2009.6.25
*/


//スプラインのポイント間の長さを取得
GetBetweenLength(spline , number)
{
  if(!instanceof(spline , SplineObject))return;
  if(spline#SPLINEOBJECT_TYPE == SPLINEOBJECT_TYPE_BSPLINE)return;
  if(spline->GetSegmentCount() >= 2)return;

  var ptc = spline->GetPointCount();
  if(number < 0 || number > ptc - 1)return;

  //開いているスプラインの場合で終点を指定した場合は、長さ0.0を返す
  if(number > ptc - 2 && !spline#SPLINEOBJECT_CLOSED)return 0.0;

  var dummy = spline->GetClone(CL_NO_HIERARCHY);

  var ct = new(BaseContainer);


  //ベジェに変更。線形の場合は変更後ハード補間
  var liner = FALSE;

  if(dummy#SPLINEOBJECT_TYPE == SPLINEOBJECT_TYPE_LINEAR)liner = TRUE;

  dummy#SPLINEOBJECT_TYPE = SPLINEOBJECT_TYPE_BEZIER;
  if(liner)SendModelingCommand(MCOMMAND_SPLINE_HARDINTERPOLATION , NULL , dummy , ct , MODIFY_ALL);


  //指定したポイントを選択
  var sel = new(BaseSelect);
  sel->Select(number);
  dummy->SetPointSelection(sel);
  //始点の設定
  SendModelingCommand(MCOMMAND_SPLINE_REORDER , NULL , dummy , ct , MODIFY_POINTSELECTION);


  //次のポイントを選択
  sel = dummy->GetPointSelection();
  sel->Select(1);
  dummy->SetPointSelection(sel);


  //選択の反転
  SendModelingCommand(MCOMMAND_SELECTINVERSE , NULL , dummy , ct , MODIFY_POINTSELECTION);


  //ポイントの削除
  SendModelingCommand(MCOMMAND_DELETE , NULL , dummy , ct , MODIFY_POINTSELECTION);


  //スプラインが閉じていれば開きます。
  if(dummy#SPLINEOBJECT_CLOSED)dummy#SPLINEOBJECT_CLOSED = FALSE;


  //長さの取得し返す
  dummy->InitLength(0);

  return dummy->GetLength();
}



main(doc , op)
{
  if(!instanceof(op , SplineObject))return;

  var ptc = op->GetPointCount();
  var i;
  for(i = 0 ; i < ptc ; i++){
    println(i , " : " , GetBetweenLength(op , i));
  }
}

今回のテストスクリプトは、全てのポイント間の長さをコンソールに表示します。
関数に渡したオブジェクトは、加工されません。

それでは、セグメント無しのBスプライン以外のスプラインで試してください。

閉じた場合です。

Length_14

0 : 222.545486
1 : 150.309906
2 : 175.901382
3 : 183.672363
4 : 219.630099
5 : 133.053955
6 : 144.192337

開いた場合です。

Length_15

0 : 222.545486
1 : 150.309906
2 : 175.901382
3 : 183.672363
4 : 219.630099
5 : 133.053955
6 : 0.000000

問題なく動作していることを確認しました。

main関数だけを次のように変更してください。
この変更スクリプトは、関数で求めたポイント間の長さの総和と、直接求めた全長をコンソールに表示します。

main(doc , op)
{
  if(!instanceof(op , SplineObject))return;

  var ptc = op->GetPointCount();
  var i;
  var sum = 0;
  var len;

  for(i = 0 ; i < ptc ; i++){
    len = GetBetweenLength(op , i);
    println(i , " : " , len);
    sum += len;
  }
  println("合計 : " , sum);

  op->InitLength(0);
  println("GetLength : " , op->GetLength());
}

開いたスプラインです。

0 : 222.545486
1 : 150.309906
2 : 175.901382
3 : 183.672363
4 : 219.630099
5 : 133.053955
6 : 0.000000
合計 : 1085.113159
GetLength : 1085.112915

閉じたスプラインです。

0 : 222.545486
1 : 150.309906
2 : 175.901382
3 : 183.672363
4 : 219.630099
5 : 133.053955
6 : 144.192337
合計 : 1229.305542
GetLength : 1129.305664

両方とも、若干の誤差があります。

|

« C4D C.O.F.F.E.E.SendModelingCommand()「始点の設定」 | トップページ | C4D C.O.F.F.E.E. スプラインのポイント間の長さが取得できるようになったので、ベジェスプラインに勾配を付けてみる。 »