2014年4月23日水曜日

Processingの3D空間で円弧

Processingにはarc関数があり、平面上で円弧を描きたい場合にはこれを使えばいいのですが、3Dで円弧を描くための関数は作られていないようです
ということで、間に合わせで作ってみました


void arc(float x, float y, float z, String vec, float start, float stop, float size) {
  final float lineDeg = radians(360 / 32);
  float px0, py0, pz0, px1, py1, pz1;
  boolean IsBreak = false;
  start = (start);
  stop  = (stop);
  
  do {
    float startRot = start;
    float stopRot  = startRot + lineDeg;
    if (stopRot > stop) { stopRot = stop; IsBreak = true; }
    
    px0 = px1 = py0 = py1 = pz0 = pz1 = 0;
    
    if (vec == "X") {
      pz0 = -sin(start)   * size;
      py0 = -cos(start)   * size;
      pz1 = -sin(stopRot) * size;
      py1 = -cos(stopRot) * size;
    }
    if (vec == "Y") {
      px0 =  sin(start)   * size;
      pz0 =  cos(start)   * size;
      px1 =  sin(stopRot) * size;
      pz1 =  cos(stopRot) * size;
    }
    if (vec == "Z") {
      px0 =  sin(start)   * size;
      py0 = -cos(start)   * size;
      px1 =  sin(stopRot) * size;
      py1 = -cos(stopRot) * size;
    }
    
    line(px0 + x, py0 + y, pz0 + z, px1 + x, py1 + y, pz1 + z);
    
    start = stopRot;
  } while (!IsBreak);
}

使い方は
  arc(0, 0, 0, "Z", radians(-45), radians(45), 30);
のような感じ
引数1-3に円の中心の位置を指定 
引数4に表示する面を文字列で指定 
引数5に開始点 引数6に終了点 をそれぞれラジアンで
引数6に円の半径を
与えます

そうすると
このように表示できます

基本的にlineのラッパー関数なので、線の色や太さ等はlineと同等に変更できます
言い換えればこの関数の前で色を変更した場合、lineなどに影響を与えるので注意してください

現在制限されていることですが
・任意の面で表示できない(X,Y,Zの3種類だけ)
・軸の正面から見て時計方向の回転だけ(start<=stopは許されない)
という点があります

1つ目については、個人的に使いたいのが3面で表示するだけで十分だったというのがあります
また、任意面で表示できるようにするのは面倒というのもあります

2つ目については、例えばstart:90 stop:0の90°の円弧を描くということはできません
例えばジャイロセンサの入力から回転を描く場合、おそらくdps等に応じて円弧の長さを変えると思いますが
startを0で固定し、ジャイロが負の方向に回転した場合はstopが負の値になる というような処理はできません
そのように使いたい場合は まず終了点を変数に保存し、終了点が負なら終了点をstartで与え、stopを0に それ以外の場合はstartを0にして終了点をstopとして与える といった判定処理が必要です

円の滑らかさは関数内lineDegを変更することで行います
Degと書きながら中身はRadianです 上記では360°を32分割しているので、正確には円ではなく32角形です
これが360角形とかになるとよほど拡大しない限りは問題なく滑らかになると思いますが、実際には32でも十分に滑らかです


また円を1周ぐるりと書く場合は、上記"start<=stop"が不可という制限から、start0 stop0ではなく、start0 stop6.283を与える必要があります(6.28は2piです)


(これくらいの関数 普通に実装されてるので実現できそうだなぁ…)

0 件のコメント:

コメントを投稿