(メモ) シェル芸グラフィクス

  • 8
    Like
  • 0
    Comment
More than 1 year has passed since last update.

2016年3月21日

今日は暇だったんで、最近マイブームのシェルを使って、超簡単なグラフィクスをやってみた。^^

しっかり別ファイルでスクリプトを組んでるから上田さんの「シェル芸」の定義にはあてはまらないけど、「シェルをつかった芸当」意味でシェル芸ってことで・・・。(^_^;)

立方体が斜めの軸を中心にして回転するの。(・∀・)

rotatingCube.png

ソースコード

yes コマンドが言わばクロックで、それを数えて回転角度に変換して(一つ目の awk コマンド)、回転角度と回転軸を生成して(二つ目の awk コマンド)、それを回転行列に変換して(Rodrigues.awk)、立方体の各点をそね回転行列で回転させた点を作って(cubePoints.awk)、立方体の点を結ぶ線分データに変換して(cubeLines.awk)、最後に画面に描く(ConsoleGraphics.awk)。隠面消去とか描画時のダブル・バッファリングとかそんな高等なことはしてない。だから綺麗な見栄えではないさ。なんくるないさぁ~ (*´ω`*)


$ yes \
| awk '{print a=(a+0.7)%360}' \
| awk '{print $1/180*PI, 1.0, 0.7, 0.7} BEGIN{PI=atan2(1,1)*4}' \
| awk -f Rodrigues.awk  \
| awk -f cubePoints.awk \
| awk -f cubeLines.awk  \
| awk -f ConsoleGraphics.awk
Rodrigues.awk
{
theta=$1 ; nx=$2 ; ny=$3 ; nz=$4
c=cos(theta) ; l_c=1-c ; s=sin(theta)
r=sqrt(nx*nx+ny*ny+nz*nz)
nx/=r ; ny/=r ; nz/=r
print \
  c+nx*nx*l_c   , nx*ny*l_c-nz*s, nx*nz*l_c+ny*s,\
  ny*nx*l_c+nz*s, c+ny*ny*l_c   , ny*nz*l_c-nx*s,\
  nz*nx*l_c-ny*s, nz*ny*l_c+nx*s, c+nz*nz*l_c
}
cubePoints.awk
function Matrix_multiply_Vector (xx,xy,xz,yx,yy,yz,zx,zy,zz, x,y,z)
  {return (xx*x+xy*y+xz*z) OFS (yx*x+yy*y+yz*z) OFS (zx*x+zy*y+zz*z)}
{
print "000", Matrix_multiply_Vector($1,$2,$3,$4,$5,$6,$7,$8,$9, -10,-10,-10)
print "001", Matrix_multiply_Vector($1,$2,$3,$4,$5,$6,$7,$8,$9, -10,-10, 10)
print "010", Matrix_multiply_Vector($1,$2,$3,$4,$5,$6,$7,$8,$9, -10, 10,-10)
print "011", Matrix_multiply_Vector($1,$2,$3,$4,$5,$6,$7,$8,$9, -10, 10, 10)
print "100", Matrix_multiply_Vector($1,$2,$3,$4,$5,$6,$7,$8,$9,  10,-10,-10)
print "101", Matrix_multiply_Vector($1,$2,$3,$4,$5,$6,$7,$8,$9,  10,-10, 10)
print "110", Matrix_multiply_Vector($1,$2,$3,$4,$5,$6,$7,$8,$9,  10, 10,-10)
print "111", Matrix_multiply_Vector($1,$2,$3,$4,$5,$6,$7,$8,$9,  10, 10, 10)
print ""
}
cubeLines.awk
{
if (NF) {x[$1]=$2 ; y[$1]=$3 ; z[$1]=$4}
else
  {
  print "clear"

  print "drawLine", x["000"],y["000"], x["001"],y["001"]
  print "drawLine", x["001"],y["001"], x["011"],y["011"]
  print "drawLine", x["011"],y["011"], x["010"],y["010"]
  print "drawLine", x["010"],y["010"], x["000"],y["000"]

  print "drawLine", x["100"],y["100"], x["101"],y["101"]
  print "drawLine", x["101"],y["101"], x["111"],y["111"]
  print "drawLine", x["111"],y["111"], x["110"],y["110"]
  print "drawLine", x["110"],y["110"], x["100"],y["100"]

  print "drawLine", x["000"],y["000"], x["100"],y["100"]
  print "drawLine", x["001"],y["001"], x["101"],y["101"]
  print "drawLine", x["010"],y["010"], x["110"],y["110"]
  print "drawLine", x["011"],y["011"], x["111"],y["111"]

  print "sleep", 300000
  }
}
ConsoleGraphics.awk
$1=="drawLine"  {drawLine(40+2*$2,12-$3,40+2*$4,12-$5)}
$1=="clear" {printf "\x1B[2J"}
$1=="sleep" {while (0<--$2) ;}

BEGIN {color="#" ; CMIN=1 ; CMAX=80 ; RMIN=1 ; RMAX=24}

function drawLine (x0,y0,x1,y1,     xmin,ymin, xmax,ymax, dx,dy, g, c0,r0, c1,r1, ci,ri, imin,imax)
  {
  if (x0<x1) {xmin=x0;xmax=x1} else {xmin=x1;xmax=x0}
  if (round(xmax)<CMIN || CMAX<round(xmin)) return

  if (y0<y1) {ymin=y0;ymax=y1} else {ymin=y1;ymax=y0}
  if (round(ymax)<RMIN || RMAX<round(ymin)) return

  dx = x1-x0 ; dy = y1-y0
  if (dx==0)
    {
    ci = round(x0)
    imin = max(RMIN,round(ymin)) ; imax = min(RMAX,round(ymax))
    for (ri=imin ; ri<=imax ; ++ri)
      {printf "\x1B[%d;%dH%s", ri, ci, color}
    }
  else if (dy==0)
    {
    ri = round(y0)
    imin = max(CMIN,round(xmin)) ; imax = min(CMAX,round(xmax))
    for (ci=imin ; ci<=imax ; ++ci)
      {printf "\x1B[%d;%dH%s", ri, ci, color}
    }
  else if (abs(dy)<abs(dx))
    {
    g = dy/dx
    c0 = max(CMIN,min(CMAX,x0)) ; r0 = y1+g*(c0-x1)
    c1 = max(CMIN,min(CMAX,x1)) ; r1 = y0+g*(c1-x0)
    c0 = r0<RMIN ? x1+(RMIN-y1)/g : RMAX<r0 ? x1+(RMAX-y1)/g : c0
    c1 = r1<RMIN ? x0+(RMIN-y0)/g : RMAX<r1 ? x0+(RMAX-y0)/g : c1
    imin = round(min(c0,c1)) ; imax = round(max(c0,c1))
    for (ci=imin ; ci<=imax ; ++ci)
      {
      ri = round(y0+g*(ci-x0))
      printf "\x1B[%d;%dH%s", ri, ci, color
      }
    }
  else
    {
    g = dx/dy
    r0 = max(RMIN,min(RMAX,y0)) ; c0 = x1+g*(r0-y1)
    r1 = max(RMIN,min(RMAX,y1)) ; c1 = x0+g*(r1-y0)
    r0 = c0<CMIN ? y1+(CMIN-x1)/g : CMAX<c0 ? y1+(CMAX-x1)/g : r0
    r1 = c1<CMIN ? y0+(CMIN-x0)/g : CMAX<c1 ? y0+(CMAX-x0)/g : r1
    imin = round(min(r0,r1)) ; imax = round(max(r0,r1))
    for (ri=imin ; ri<=imax ; ++ri)
      {
      ci = round(x0+g*(ri-y0))
      printf "\x1B[%d;%dH%s", ri, ci, color
      }
    }
  }

function min (u,v) {return u<v ? u : v}
function max (u,v) {return u>v ? u : v}

function abs   (v) {return 0<=v ? v : -v}
function floor (v) {return int(v) - (0<v ? 0 : 1)}
function ceil  (v) {return int(v) + (v<0 ? 0 : 1)}
function round (v) {return int(v + (0<v ? 0.5 : -0.5))}