\section{視界とグラフィックス}
\markright{\arabic{section}. 視界とグラフィックス}

\subsection{視界(viewing)}
{\bf viewing}オブジェクトは、viewing座標系を処理する。
この座標系の原点は仮想カメラの位置に置かれる。
{\em -z}軸方向がオブジェクトの視線方向で、xy平面が投影画面である。
{\bf viewing}が{\bf cascaded-coords}クラスを継承するので、
{\bf :translate}や{\bf :rotate}や{\bf :transform}のような
座標変換メッセージを受け付ける。
また、{\bf cascaded-coords}から得られる他のオブジェクトを張り付けることができる。
したがって、移動物体上のカメラシステムのシミュレーションができる。
{\bf viewing}の主な目的は、ワールド座標系で表現されるベクトルを
カメラ座標系に変換することである。
変換は、一般の座標変換に対して逆方向で与えられる。
このローカル座標系内のベクトルはワールド座標系における表現に変換される。
したがって、{\bf viewing}は{\tt viewcoords}スロットに逆変換された左手系変換を持つ。
このスロットは、viewing座標系として普通参照される。

\begin{figure}
\begin{center}
\includegraphics[height=10cm]{fig/viewcoords.ps}
%\epsfile{file=fig/viewcoords.ps,height=10cm}
\end{center}
\caption{viewing座標系と投影画面}
\end{figure}

\begin{refdesc}

\classdesc{viewing}{cascaded-coords}{(viewcoords)}{
viewing変換を定義する。}

\methoddesc{:viewpoint}{}{
この{\bf viewing}の原点のベクトル位置を返す。}

\methoddesc{:view-direction}{}{
{\bf viewing}の原点から画面の中心までのベクトルを返す。
これは、viewing座標系のz軸方向である。}

\methoddesc{:view-up}{}{
ワールド座標系におけるこの{\bf viewing}のy軸ベクトルを返す。
y軸は、{\bf viewport}の上方である。}

\methoddesc{:view-right}{}{
ワールド座標系におけるこの{\bf viewing}のx軸ベクトルを返す。
x軸は、{\bf viewport}の水平右方向である。}

\methoddesc{:look}{from \&optional (to \#f(0 0 0))}{
{\bf :look}は、その目が{\em from}に位置されており、{\em to}の位置を
見ているとしてviewing座標系を設定する。}

% \metdesc{:makeviewcoords}{ ax ay az vpoint}
\longdescription{メソッド}{:init}{\&key \= (target \#f(0 0 0)) \\
\> (view-direction nil) \\
\> (view-up \#f(0.0 0.0 1.0)) \\
\> (view-right nil) \\
\> \&allow-other-keys}{
{\bf viewing}は、{\bf cascaded-coords}を継承するので、{\em :pos}や{\em :rot}や{\em :euler}
や{\em :rpy}などの{\em :init}のパラメータはすべてviewing座標系の位置や姿勢を
指定することに使用できる。
しかしながら、viewingの{\em :init}は回転を決定する簡単な方法を持っている。
もし、{\em :target}だけが与えられたとき、視線方向は視点から{\em target}位置
の方向に決定され、{\em :view-right}ベクトルはワールド座標系のxy平面に平行な
x軸に決定される。
{\em :view-direction}を{\em :target}の代わりに指定しても同じ様な
効果を得られる。
もし、{\em :view-up}または{\em :view-right}パラメータを{\em :target}あるいは
{\em :view-direction}に加えて指定するならば、3つの回転パラメータをすべて
自分自身で決定することができる。}

\end{refdesc}

\subsection{投影}

{\bf parallel-projection}と{\bf perspective-projection}クラスは、
投影変換を処理する。この変換は4X4の行列で表現される。すなわち、変換は
3次元の同次座標系で与えられる。
{\bf projection}クラスは、両方のクラスの抽象クラスである。
これらの投影クラスは、viewingクラスを継承しているので、
2つの座標変換（ワールド座標からviewing座標系への変換と投影変換）を
同時に実行することができる。
3Dベクトルと{\tt :project3}メッセージを投影オブジェクトに送ることにより、
4要素の実数ベクトル返す。
{\bf homo2normal}関数は、この同次ベクトルを標準のベクトル表現に変換
するために使用される。
その結果は、標準デバイス座標系(NDC)と呼ばれる座標系上に表現される
ベクトルである。
その中で、見えるベクトルはそれぞれのx,y,z次元において-1から1までの
範囲で表される。
ロボット世界の本当のカメラをシミュレートするために、
{\bf perspective-projection}は{\bf parallel-projection}よりも多く使用される。
{\bf perspective-projection}は、定義されているパラメータが少し多い。
{\tt screenx}と{\tt screeny}は、見える物体が投影されるviewing平面の上のwindowの大きさで、
大きな画面と広い空間が投影される。
{\tt viewdistance}は、視点とview平面との距離を定義しているが、
視角にも関係する。
{\tt viewdistance}を大きくすると、view平面のwindowに狭い範囲が投影される。
{\tt hither}と{\tt yon}パラメータは、クリップする平面の前面と後面の距離を
定義する。
これら2つの平面の外側に位置するオブジェクトは、クリップから除外される。
実際に、このクリップ処理は{\bf viewport}オブジェクトによって実現されている。

\begin{refdesc}

\classdesc{projection}{viewing}{(screenx screeny hither yon projection-matrix)}{
4x4行列であらわされる投影変換を定義する。}

\methoddesc{:projection}{\&optional pmat}{
もし、{\em pmat}が与えられたならば、
{\tt projection-matrix}のスロットに設定する。
{\bf :projection}は、現在の4x4投影行列を返す。}

\methoddesc{:project}{vec}{
{\em vec}は、4要素を持つ3次元同次ベクトルである。
{\em vec}は、投影行列により変換される。
そして、変換された結果である同次表現が返される。}

\methoddesc{:project3}{vec}{
{\em vec}は、標準の3Dベクトル。
{\em vec}は、投影行列により同次化され変換される。
そして、変換された結果である同次表現が返される。}

\methoddesc{:view}{vec}{
{\em vec}にviewing変換と投影変換を連続的に適用する。
そして、変換された結果である同次表現が返される。}

\methoddesc{:screen}{xsize (\&optional (ysize xsize))}{
viewing画面の大きさを変える。
大きくすると、広いviewが得られる。}

\methoddesc{:hither}{depth-to-front-clip-plane}{
視点からクリップ前面までの距離を決定する。
このクリップ前面よりも前にあるオブジェクトはクリップから除外される。}

\methoddesc{:yon}{depth-to-back-clip-plane}{
視点からクリップ後面までの距離を変える。
このクリップ後面よりも後ろにあるオブジェクトはクリップから除外される。}

\methoddesc{:aspect}{\&optional ratio}{
アスペクト比は、screen-yとscreen-xとの比である。
もし、{\em ratio}が与えられたならば、
アスペクト比は変えられ、screen-yはscreen-x * {\em ratio}に設定される。
{\bf :aspect}は、現在のアスペクト比を返す。}
\longdescription{メソッド}{:init}{\&key \= (hither 100.0) \\
\> (yon 1000.0) \\
\> (aspect 1.0) \\
\> (screen 100.0) \\
\> (screen-x screen) \\
\> (screen-y (* screen-x aspect)) \\
\> \&allow-other-keys}{
{\bf viewing}と{\bf projection}を初期化する。}

\vspace{5mm}

\classdesc{parallel-viewing}{projection}{}{
平行投影を定義する。
{\bf hid}(陰線消去関数)は平行投影では扱うことが出来ない。}

\metdesc{:make-projection}{}

\classdesc{perspective-viewing}{projection}{(viewdistance)}{
透視投影変換を定義する。}

\metdesc{:make-projection}{}

\methoddesc{:ray}{u v}{
視点から正規化画面の上にある{\em (u,v)}への単位方向ベクトルを返す。}

\methoddesc{:viewdistance}{\&optional vd}{
{\tt viewdistance}は、視点から画面迄の距離である。
もし、{\em vd}が与えられたならば、{\tt viewdistance}に設定される。
{\tt viewdistance}は、カメラの焦点距離と一致する。
{\em vd}を大きくすれば、ズームアップされたviewを得ることができる。
{\bf :viewdistance}は、現在の{\tt viewdistance}を返す。}

\methoddesc{:view-angle}{\&optional ang}{
画面の対角線を見込む角度が{\em ang}ラジアンであるように画面の大きさを設定する。
20度(約0.4ラジアン)から50度(約0.9ラジアン)までの角度が自然な透視view
を生成することができる。
角度を大きくすると歪んだviewを生成する。
そして、狭くすると直角(平行)viewingのような平坦なviewが生成される。
{\bf :view-angle}は、現在の視角あるいは新しい視角をラジアンで返す。}

\methoddesc{:zoom}{\&optional scale}{
もし、{\em scale}が与えられたならば、画面は{\em scale}によって
現在の大きさを相対的に変化させる（{\tt viewdistance}は変化しない）。
もし、{\em scale}に0.5を与えるならば、以前のviewより2倍広いviewを得られる。
{\bf :zoom}は、新しい視角をラジアンで返す。}

\methoddesc{:lookaround}{alfa beta}{
視点を移動し回転させる。
回転中心は、視線の上で{\tt hither}平面と{\tt yon}平面の中間点
に与えられる。
viewing座標系は、ワールド座標系のz軸回りに{\em alfa}ラジアン回転し、
ローカル座標系のx軸回りに{\em beta}ラジアン回転される。
{\bf :lookaround}は、{\bf viewing}の中心にあるオブジェクト回りに視線を
動かすことができる。}

\methoddesc{:look-body}{bodies}{
視線、画面の大きさおよびhither/yonをすべての{\em bodies}に適合するviewport
となるよう変える。視点は変化しない。
視線は、すべての{\em bodies}のbounding boxの中心を通る視線から選択される。}

\metdesc{:init}{\&key (viewdistance 100.0) \&allow-other-keys}

\end{refdesc}

\subsection{Viewport}

{\bf viewport}クラスは、正規デバイス座標系(NDC)の中の3次元viewportのクリップ
を実行する。そして、デバイスに依存する座標系に結果を作る。
{\bf viewport}は、画面上の見える四角領域の境界表現である。
{\bf viewport}の物理的な大きさ（x軸とy軸方向のドット数）は、
{\bf :init}メッセージの中の{\em :width}と{\em :height}との引き数
で与えられなければならない。
{\em :xcenter}と{\em :ycenter}引き数は、viewportの物理的な位置を決定する。
画面の原点からのそれぞれの次元が絶対的に与えられているテクトロニクス4014
のような基本的なディスプレイデバイスを使っているとき、これら2つのパラメータは、実際に画面の上にオブジェクトを描く位置を決定する。
もし、位置が親windowから相対的に決まるXwindowのような精巧なディスプレイ
デバイスを使っているなら、
viewportを動かすためにviewportのパラメータを変える必要はない。
なぜなら、これらのパラメータは、実際のディスプレイ位置に依存しないからである。。

{\bf viewport}クラスは、四角領域の左下をviewportの原点と仮定している。
そして、y軸は上方向に伸びているとする。
しかし、多くのwindowシステムやディスプレイデバイスでは原点を左上とし、
y軸が下方向に伸びているとしている。
この問題を回避するために、{\em :height}パラメータに負の値を与えればよい。

\begin{refdesc}

\funcdesc{homo-viewport-clip}{v1 v2}{
{\em v1}と{\em v2}は、4要素を持つ同次ベクトルであって、
3次元空間の線分として表現される。
その線分は、$x=-1, x=1, y=-1, y=1, z=0, z=1$の境界でクリップされる。
そして、2つのベクトルのリストを返す。
もし、その線分が{\bf viewport}の外側に完全に置かれているならば、
NILを返す。}

\classdesc{viewport}{coordinates}{}{
viewport変換は、デバイスで指定される座標系にNDC（正規化デバイス座標系）を作る。
{\bf coordinates}クラスを継承しているため、{\bf viewport}はサイズと投影画面の
相対位置を定義している。}

\methoddesc{:xcenter}{\&optional xcenter}{
この{\bf viewport}のx軸の中心を返す。
もし、{\em xcenter}が与えられていれば、設定を行う。}

\methoddesc{:ycenter}{\&optional ycenter}{
この{\bf viewport}のy軸の中心を返す。}

\methoddesc{:size}{\&optional size}{
この{\bf viewport}のx軸とy軸方向の大きさのリストを返す。}

\methoddesc{:width}{\&optional width}{
この{\bf viewport}の幅を{\em width}に設定する。}

\methoddesc{:height}{\&optional height}{
この{\bf viewport}の高さを{\em height}に設定する。}

\methoddesc{:screen-point-to-ndc}{p}{
{\em p}は、物理的画面の中の位置を表現する実数ベクトルである。
{\em p}は、正規化デバイス座標系(NDC)の中での表現に変換される。}

\methoddesc{:ndc-point-to-screen}{p}{
この{\bf viewport}のNDC表現である{\em p}を画面の物理的位置に変換する。}

\methoddesc{:ndc-line-to-screen}{p1 p2 \&optional (do-clip t)}{
2つの3次元ベクトル{\em p1}と{\em p2}は、NDCの中の線分を定義する。
これらの2つの端点は、画面空間の表現に変換される。
もし、{\em do-clip}がnon-NILなら、その線分はクリップされる。}

\methoddesc{:init}{\&key (xcenter 100) (ycenter 100) (size 100) (width 100) (height 100)}{
新しい{\bf viewport}オブジェクトを作る。}

\end{refdesc}

\subsection{Viewer}
画面の上に描画するためには、4つのオブジェクトが必要である。
1つは描かれたオブジェクト、2つはviewing座標系と投影で定義される{\bf viewing}、
3つはNDCの中でのクリップ処理のための{\bf viewport}とNDCから物理的画面座標系への
変換、4つは
物理的ディスプレイデバイスの上に描画関数を実行する{\bf viewsurface}。
{\bf viewer}オブジェクトは、{\bf viewing}と{\bf viewport}と{\bf viewsurface}
オブジェクトを持ち、
座標系変換を連続的に制御する。
\ref{Drawings}節に記述される{\bf draw}と{\bf hid}関数は{\bf viewer}の
インスタンスを使用する。

\begin{refdesc}

\classdesc{viewer}{object}{(eye :type viewint) \\
                        \> (port :type viewport) \\
                        \> (surface :type viewsurface)}{
viewingからviewportを経由してviewsurfaceへ移るCascaded Coordinatesの変換を定義する。}

\methoddesc{:viewing}{\&rest msg}{
もし、{\em msg}が与えられたならば、{\em msg}は{\bf viewing}{\tt (eye)}オブジェクト
に送られる。そうでなければ、{\bf viewing}{\tt (eye)}オブジェクトが返される。}

\methoddesc{:viewport}{\&rest msg}{
もし、{\em msg}が与えられたならば、{\em msg}は{\bf viewport}{\tt (port)}オブジェクト
に送られる。そうでなければ、{\bf viewport}{\tt (port)}オブジェクトが返される。}

\methoddesc{:viewsurface}{\&rest msg}{
もし、{\em msg}が与えられたならば、{\em msg}は{\bf viewsurface}{\tt (surface)}オブジェクト
に送られる。そうでなければ、{\bf viewsurface}{\tt (surface)}オブジェクトが返される。}

\methoddesc{:adjust-viewport}{}{
{\bf viewsurface}の大きさが変えられたとき、{\bf :adjust-viewport}は
{\tt port}に固有のメッセージを送ることにより{\bf viewport}の変換を変える。}

\methoddesc{:resize}{width height}{
{\bf viewsurface}に{\tt :resize}メッセージを送り、{\bf viewport}に{\tt :size}メッセージを送る
ことによりviewsurfaceの大きさを変える。}

\methoddesc{:draw-line-ndc}{p1 p2 \&optional (do-clip t)}{
NDCの中に定義される2つの端点{\em p1,p2}を結ぶ線を描く。}

\methoddesc{:draw-polyline-ndc}{polylines \&optional color}{
NDCの中に定義される端点を結ぶ多角形を描く。}

\methoddesc{:draw-star-ndc}{center \&optional (size 0.01) color}{
NDCの中に十字マークを描く。}

\methoddesc{:draw-box-ndc}{low-left up-right \&optional color}{
NDCの中に四角形を描く。}

\methoddesc{:draw-arc-ndc}{point width height angle1 angle2 \&optional color}{
NDCの中に円弧を描く。
この{\bf viewer}に結び付く{\bf viewsurface}オブジェクトは、{\bf :arc}メッセージを
受けなければならない。}

\methoddesc{:draw-fill-arc-ndc}{point width height angle1 angle2 \&optional color}{
NDCの中に塗り潰し円弧を描く。}

\methoddesc{:draw-string-ndc}{position string \&optional color}{
NDCの中に定義される{\em position}に{\em string}を描く。}

\metdesc{:draw-image-string-ndc}{position string \&optional color}

\metdesc{:draw-rectangle-ndc}{position width height \&optional color}

\metdesc{:draw-fill-rectangle-ndc}{point width height \&optional color}

\methoddesc{:draw-line}{p1 p2 \&optional (do-clip t)}{
ワールド座標系に定義される2つの端点{\em p1,p2}を結ぶ線を描く。}

\methoddesc{:draw-star}{position \&optional (size 0.01) color}{
ワールド座標系の{\em position}位置に十字マークを描く。}

\methoddesc{:draw-polyline}{vlist \&optional color}{
ワールド座標系の{\em vlist}端点を結ぶ多角形を描く。}

\methoddesc{:draw-box}{center \&optional (size 0.01)}{
ワールド座標系の{\em center}に四角形を描く。}

\methoddesc{:draw-arrow}{p1 p2}{
{\em p1}から{\em p2}へ向けての矢印を描く。}

\metdesc{:draw-edge}{edge}

\metdesc{:draw-edge-image}{edge-image}

\metdesc{:draw-faces}{face-list \&optional (normal-clip nil)}

\metdesc{:draw-body}{body \&optional (normal-clip nil)}

\methoddesc{:draw-axis}{coordinates \&optional size}{
{\em coordinates}で定義される軸を{\em size}の長さで描く。}

\methoddesc{:draw}{\&rest things}{
3次元の幾何学オブジェクトを描く。
もし、オブジェクトが3次元ベクトルならば、その位置に小さな十字マークを描く。
もし、3次元ベクトルのリストであれば、多角形を描く。
もし、{\em thing}が{\tt :draw}メッセージを受けたならば、
この{\bf viewer}を引き数としてそのメソッドが呼び出される。
もし、オブジェクトが{\tt :drawners}メソッドを定義しているならば、
{\bf :draw}メッセージは{\tt :drawners}の結果に送られる。
{\tt line, edge, polygon, face}および{\tt body}オブジェクトは、
{\bf viewer}に定義されている{\bf :draw-xxx}(xxxにそのオブジェクトのクラス名が入る)
メソッドによって描かれる。}

\methoddesc{:erase}{\&rest things}{
背景色で{\em things}を描く。}

\methoddesc{:init}{\&key viewing viewport viewsurface}{
{\em viewing, viewport}および{\em viewsurface}をこの{\bf viewer}のスロット
{\tt eye, port}と{\tt surface}に設定する。}

\longdescription{関数}{view}{\&key \= (size 500) (width size) (height size) \\
\> (x 100) (y 100) \\
\> (title "eusx") \\
\> (border-width 3) \\
\> (background 0) \\
\> (viewpoint \#f(300 200 100)) (target \#f(0 0 0)) \\
\> (viewdistance 5.0) (hither 100.0) (yon 10000.0) \\
\> (screen 1.0) (screen-x screen) (screen-y screen) \\
\> (xcenter 500) (ycenter 400)}{
新しい{\bf viewer}を作り、{\bf *viewer*}リストに置く。}

\end{refdesc}

\newpage
\subsection{\label{Drawings}描画}

\begin{refdesc}

\funcdesc{draw}{\&optional viewer \&rest thing}{
{\em viewer}に{\em thing}を描く。
{\em thing}は、座標系、立体、面、エッジ、ベクトル、2つのベクトルのリストのどれでも可能である。
{\tt (progn (view) (draw (make-cube 10 20 30)))}
は、xwindowに立方体を描く。}


\funcdesc{draw-axis}{\&optional viewer size \&rest thing}{
{\em viewer}の中に{\em thing}の座標系の軸を{\em size}の長さで描く。
{\em thing}は、座標系から得られるどのオブジェクトでも可能である。}

\funcdesc{draw-arrow}{p1 p2}{
{\bf *viewer*}に{\em p1}から{\em p2}に向かう矢印を描く。}

\funcdesc{hid}{\&optional viewer \&rest thing}{
{\em viewer}に陰線処理された画像を描く。
{\em thing}は、{\tt face}または{\tt body}が可能である。}

\funcdesc{hidd}{\&optional viewer \&rest thing}{
陰線を点線で描くことを除いて、{\bf hid}と同じである。}

\funcdesc{hid2}{body-list viewing}{
edge-imageオブジェクトで表現される陰線処理画像を生成する。
その結果は{\bf *hid*}に置かれる。}

\funcdesc{render}{\&key bodies faces (viewer *viewer*) (lights *light-sources*)\\
(colormap *render-colormap*) (y 1.0)}{
{\em bodies}と{\em faces}にレイトレーシングを行い、陰面消去した画像を生成する。
{\bf viewing, viewport}および{\bf viewsurfaceは}、{\em viewer}から得られる。
{\em lights}は、{\tt light-source}（光源）オブジェクトのリストである。
{\em colormap}は、Xwindowの{\bf colormap}オブジェクトである。
それぞれの{\em bodies}と{\em faces}は、割り当てられるカラー属性を
持たなければならない。
{\em colormap}に定義されているカラーLUTの名前を{\tt :color}メッセージで
送ることによりカラー属性を設定できる。
一般にこの関数は、Xlib環境下でのみ働く。
{\tt demo/renderdemo.l}のサンプルプログラムを見ること。}

\funcdesc{make-light-source}{pos \&optional (intensity 1.0)}{
{\em pos}の位置に光源オブジェクトを作る。
{\em intensity}は、デフォルトの光の強さを増す拡大比である。
もっと正確に強さを決定するためには、光源の{\tt :intensity}メソッドを
使用する。}

\macrodesc{tektro}{file \&rest forms}{
{\tt *tektro-port*}ストリームのために{\em file}をオープンし、
{\em forms}を評価する。
これは、tektro描画の出力を直接{\em file}に書き込むために使用される。}

\macrodesc{kdraw}{file \&rest forms}{
{\bf kdraw}は、{\tt kdraw}または{\tt idraw}で読み込めるポストスクリプトファイルを
生成するためのマクロ命令である。
{\bf kdraw}は、{\tt :output}モードで{\em file}をオープンし、
{\tt *viewer*}を置き換えるためのkdraw-viewsurfaceとviewportを
作り、{\em forms}を評価する。
それぞれの{\em forms}は、{\tt draw}や{\tt hid}のような描画関数の
どれかを呼び出す。
これらの{\em forms}からの描画メッセージは、{\tt kdraw-viewsurface}に
直接出力される。この出力は{\tt idraw}や{\tt kdraw}で認識できる
ポストスクリプト表現にメッセージを変換する。
そして、{\em file}に蓄積する。
{\tt idraw}または{\tt kdraw}が呼び出され{\em file}がオープンされたとき、
EusViewer windowに書いたものと同一の図形を見ることができる。
その図形は、{\tt idraw}の機能で変更することができる。
そして、最終描画は{\tt epsfile}環境を用いることにより\LaTeX ドキュメント
に組み込むことができる。
この機能は、"llib/kdraw.l"のファイルに記述されている。}

\macrodesc{pictdraw}{file \&rest forms}{
{\bf pictdraw}は、MacintoshのPICTフォーマットで画像ファイルを
生成するためのマクロである。
{\bf pictdraw}は、{\em file}を{\tt :output}モードでオープンし、
pictdraw-viewsurfaceを作り、{\tt *viewer*}のviewportに置き換え、
{\em forms}を評価する。
{\em forms}は、それぞれ{\tt draw}あるいは{\tt hid}のような描画関数のどれかを
呼び出すものである。
これらの書式からの描画メッセージは、{\tt kdraw-viewsurface}に
直接出力された後、PICTフォーマットへのメッセージに変換され,
{\em file}へ蓄積される。
このPICTフォーマットは、Macintoshの{\tt macdraw}や{\tt teachtext}で
認識することができる。}

\funcdesc{hls2rgb}{hue lightness saturation \&optional (range 255)}{
HLS(Hue, Lightness, Saturation)で表現される色を、RGB表現に変換する。
HLSは、しばしばHSLとして参照される。
{\em hue}は、rainbow circle(0から360)の色で表現される。
0が赤で45が黄で120が緑で240が青で270が紫そして360が再び赤となる。
{\em lightness}は、0.0から0.1の値を持ち、黒から白までの明るさを表現する。
{\em lightness}が0のときは、{\em hue}や{\em saturation}にかかわらず
黒となる。そして、{\em lightness}が1のときは、白となる。
{\em saturation}は、0.0から1.0までの値を持ち、色の強さを表現する。
{\em saturation}の値が大きいと鮮明な色調を生成し、小さい値は弱く濁った色調
を生成する。
{\em range}は、RGB値の限界を示す。
もし、それぞれの色に8ビットの値が割り当てられているカラーディスプレイ
を使っているならば、{\em range}は255とすべきである。
もし、RGBに16ビットの整数が仮想的に割り当てられているXwindowを使って
いるならば、{\em range}は65536とすべきである。
HSVとHLSとの違いに注意すること。
HLSでは、鮮明な(rainbow)色は{\tt lightness=0.5}で定義されている。}

\funcdesc{rgb2hls}{red green blue \&optional (range 255)}{
RGBの色表現を、HLS表現に変換する。}

\end{refdesc}

\subsection{アニメーション}
\index{animation}
EusLispのアニメーションは、グラフィックアクセラレータを持たない
普通のワークステーション上での擬似リアルタイムグラフィックス機能を備えている。
その基本的な考え方は、長い時間かかって生成された1連の画像を高速に
再表示することである。
画像は2つの方法で保存される。
1つは、完全なピクセル画像を持つたくさんのXwindow pixmapを保存する。
もう1つは、陰線処理で得られる線分データを保存する。
前者は、高速で陰面処理された画像を表示するための方法であるが、
長いアニメーションではたくさんのメモリーをX serverに要求するため
適さない。
後者は、メモリーが少なくて済み、データをディスクに蓄積するのに適する。
しかし、線分の数が増加したならば、性能を悪化させる。

他の方法として、描かれるオブジェクトの構成を得て、
{\bf *viewer*}に描画を生成する関数をユーザーが作ることもできる。
{\bf pixmap-animation}は、{\em count}引数で指定された数と同じ回数この関数を呼び出す。
それぞれの呼び出し後、Xwindowと仮定される{\tt viewsurface}の内容は、
新しく作られたXwindow pixmapにコピーされる。
これらのpixmapは、{\bf playback-pixmap}で再表示される。
同様に、{\bf hid-lines-animation}は{\bf hid}の結果から見える線分を抜き出し、
リストに蓄積する。
そのリストは、{\bf playback-hid-lines}によって再表示される。

以下に示す関数は、"llib/animation.l"に定義されており、
"llib/animdemo.l"の中にはETA3 マニピュレータのモデルに関して
{\bf hid-lines-animation}を用いたアニメーションの
サンプルプログラムを含んでいる。

\begin{refdesc}

\macrodesc{pixmap-animation}{count \&rest forms}{
{\em forms}は、{\em count}回評価される。
それぞれの評価後、{\tt *viewsurface*}の内容は新しいpixmapにコピーされる。
{\em count}枚の{\bf pixmap}のリストが、返される。}

\funcdesc{playback-pixmaps}{pixmaps \&optional (surf *viewsurface*)}{
{\em pixmaps}リストのなかの{\bf pixmap}はそれぞれ、
%{\em wait}$\mu$秒の間隔をおいて
{\em surf}に連続的にコピーされる。}

\macrodesc{hid-lines-animation}{count \&rest forms}{
{\bf hid}への呼び出しを含む{\em forms}が{\em count}回評価される。
それぞれの評価後、{\bf *hid*}が持つ{\bf hid}の結果は検索され、
見える線分は2点一組のリストの形で集められる。
{\em count}長さのリストが返される。}

\funcdesc{playback-hid-lines}{lines \&optional (view *viewer*)}{
{\em lines}は、2点一組のリストである。
{\em view}の上に線分を連続的に描く。
他のpixmapを割り当てるときにフリッカーフリーアニメーションを生成するために
2重バッファ技法が使用される。}

\funcdesc{list-visible-segments}{hid-result}{
{\em hid-result}のedge画像のリストから見える線分を集める。}

\end{refdesc}

\newpage
