ブレゼンハムのアルゴリズム

ブレゼンハムのアルゴリズム(Bresenham's line algorithm)は、与えられた始点と終点の間に連続した点を置き、近似的な直線を引くためのアルゴリズム。ブレゼンハムの線分描画アルゴリズム、ブレゼンハムアルゴリズムとも。コンピュータのディスプレイに直線を描画するのによく使われ、整数の加減算とビットシフトのみで実装できるので多くのコンピュータで使用可能である。コンピュータグラフィックスの分野の最初期のアルゴリズムの1つである。これを若干拡張すると、円を描くことができる。
アンチエイリアスをサポートした直線描画アルゴリズム（例えば、Xiaolin Wu's line algorithm）もあるが、ブレゼンハムのアルゴリズムの高速性と単純さは今も重要である。プロッターやビデオカードのGPUといったハードウェアで使用されている。ソフトウェアでは多くのgraphics libraryで使用している。非常に単純なので、ビデオカードのファームウェアなどに実装されていることが多い。

**歴史**
1962年、IBMのジャック・ブレゼンハムが開発した。2001年、ブレゼンハムは次のように記している。
当時私はサンノゼのIBMの開発研究室で働いていた。Calcomp製プロッターCalcomp plotter が1407タイプライター型コンソール経由で IBM 1401 に接続されていた。このアルゴリズムは1962年夏には使われており、開発したのは1カ月ほど前だったかもしれない。当時プログラムは無償で交換されるものだったので、Calcomp（Jim Newland と Calvin Hefte）もそのコピーを持っていた。1962年秋、私がスタンフォードに戻ったときもコピーをスタンフォードの計算センターのライブラリに入れた。
この直線描画ルーチンについて、1963年コロラド州デンバーで開催されたACM全国大会で発表した。ただし、その年は発表内容が出版されることはなく、単に日程表などに私の発表の題名が掲載されただけだった。その後IBMの Systems Journal が発表した論文を掲載したいと申し出てきたので、よろこんで提供し、1965年に出版された。
ブレゼンハムのアルゴリズムは後に修正を加えられ、円を描画するアルゴリズムにもなっている。こちらのアルゴリズムは midpoint circle algorithm などと呼ばれている。

**アルゴリズム**
ブレゼンハムのアルゴリズムで描画した直線の例。左上端の格子が (0,0) で、直線は (1,1) から (11,5) までひかれている。
以下が成り立つものとして説明していく。- 左上端が原点 (0,0) で、ピクセルの座標は右方向と下方向に向かって大きくなる（例えば、(7,4) という座標のピクセルは (7,5) という座標のピクセルに接して上にある）。- 各ピクセルの中心が、その整数座標に正確に対応するものとする。
いま、x が横方向、y が縦方向の座標であるとして、直線の両端のピクセルの座標が (x0, y0) と (x1, y1) として与えられたとする。
まず、1つの象限のみを対象とし、線分は右下に向かう方向のみ（すなわち、x0≤x1 かつ y0≤y1）で、その傾きは1未満（すなわち、 の方が  より長い）の場合に限って説明する。この場合、 と  の間の x のそれぞれの位置について、（このアルゴリズムでの計算で） y の位置が一意に定まり、 と  の間の y のそれぞれの位置には複数のピクセルが描画されうることになる。
ブレゼンハムのアルゴリズムでは、x に対応した y の値（小数値）を計算し、それに最も近い整数値を描画すべきピクセルの座標とする。したがって、1つ前の x で求めた y の整数値と同じか、または1だけ増加することになる。描画すべき線分の方程式は次のようになる。

x を順次与えて y を求め、最も近い整数値にするので、この式を次のように変形する。

傾き  は線分の両端の座標のみから求められるので事前に計算しておくことができる。x を順次増やして y を求めるが、最初の値は  であり、それに傾きを繰り返し加算すればよいことになる。
実際には傾きを加算し続けると精度が悪くなる（カハンの加算アルゴリズム参照）。しかし y を整数値に丸めた値と傾きを加算し続けた値の差のみを保持するようにすれば、その値は -0.5 から 0.5 の間で変化するだけであり、精度は悪くならない。すなわち、x を1ずつ増加させ、差に傾きを加算した結果が 0.5 を超えたら y をインクリメントして差から1を引けばよい。
以下の擬似コードでは、plot(x,y) でピクセル描画を行い、abs は絶対値を返すものとする。
function line(x0, x1, y0, y1)
int deltax := x1 - x0
int deltay := y1 - y0
real error := 0
real deltaerr := abs (deltay / deltax)    // deltax != 0 と仮定（垂直な線は扱わない）
// この除算は分数を保持する形で行う必要がある。
int y := y0
for x from x0 to x1
plot(x,y)
error := error + deltaerr
if error ≥ 0.5 then
y := y + 1
error := error - 1.0

**最適化**
この技法の問題は、error や deltaerr が分数であるためコンピュータでは計算が遅くなる点であり、さらに浮動小数点数を使った場合は加算によって誤差が蓄積していく点である。整数のみを使った方が高速化され正確になる。そこで上の例で分数または小数になっている全ての数（定数0.5も含む）に deltax をかけて整数にするという技法を使う。ただしそうするとメインループ内で除算が必要になる。そのため error の初期値を変更し、初期値を0として0.5を越えるまでカウントアップするのではなく、初期値を0.5（に deltax をかけた値）にし、0になるまでカウントダウンするように変更する。新たなプログラムの擬似コードは次のようになる。
function line(x0, y0, x1, y1)
boolean steep := abs(y1 - y0) > abs(x1 - x0)
if steep then
swap(x0, y0)
swap(x1, y1)
if x0 > x1 then
swap(x0, x1)
swap(y0, y1)
int deltax := x1 - x0
int deltay := abs(y1 - y0)
int error := deltax / 2
int ystep
int y := y0
if y0  abs(x1 - x0)
if steep then
swap(x0, y0)
swap(x1, y1)
int deltax := abs(x1 - x0) // 修正
int deltay := abs(y1 - y0)
int error := deltax / 2
int ystep
int y := y0

int inc // 追加
if x0 swap を排除できる。
function line(x0, y0, x1, y1)
dx := abs(x1-x0)
dy := abs(y1-y0) 
if x0  -dy then 
err := err - dy
x0 := x0 + sx
end if
if e2  0
y = y+1
plot(x,y)
D = D + (2*dy-2*dx)
else
plot(x,y)
D = D + (2*dy)
で表される直線の (0,1) から (6,4) までをこのアルゴリズムで計算した場合の経過を以下に示す。dx=6、dy=3 である。- D=2*3-6=0- plot(0,1)- 1から6までループ
** x=1: D≤0: plot(1,1), D=6
** x=2: D>0: y=2, plot(2,2), D=6+(6-12)=0
** x=3: D≤0: plot(3,2), D=6
** x=4: D>0: y=3, plot(4,3), D=6+(6-12)=0
** x=5: D≤0: plot(5,3), D=6
** x=6: D>0: y=4, plot(6,4), D=6+(6-12)=0
この描画結果を右図に示す。描画は座標上の交点（青い点）またはピクセル（黄色い四角形）で示されている。

**全象限について**
ここまで述べてきたのは、第一象限かつ、直線の傾きが45度以下の場合（第一八分円）のみについてである。したがって、直交座標系のあらゆる場合を網羅するには全部で8つのケースを考慮する必要がある。

**類似のアルゴリズム**
ブレゼンハムのアルゴリズムは、label=DDAを若干修正したものと見ることができる（DDAはオーバーラップしない多角形、すなわちポリゴンのラスタライズで使われる）。
除算の代わりに増分誤差を使う原理は、グラフィックスにおいて他にも応用されている。例えば、テクスチャマッピングでのU,V座標(:en:UV mapping)計算に使うことができる。また、ゲームでの3次元地形描画でもこの原理が使われることがある。
IBMの Alan Murphy はこのアルゴリズムを拡張した太い直線の描画アルゴリズムを開発した。

**脚注**

**参考文献**
 url= http://ieeexplore.ieee.org/xpl/tocresult.jsp?isnumber=5388471&punumber=5288519-  "The Bresenham Line-Drawing Algorithm", by Colin Flanagan- notes=A very optimized version of the algorithm in C and assembly for use in video games with complete details of its inner workings

**関連文献**
  Patrick-Gilles Maillot's Thesis MICAD '87 proceedings on CAD/CAM and Computer Graphics, page 591 - ISBN 2-86601-084-1. ブレゼンハムのアルゴリズムを応用して3次元グラフィックスで隠れて見えない直線を削除する技法を示したもの-  Line Thickening by Modification To Bresenham's Algorithm, A.S. Murphy, IBM Technical Disclosure Bulletin, Vol. 20, No. 12, May 1978. ブレゼンハムのアルゴリズムを拡張して太い線を描画する技法を示したもの

**外部リンク**
  Didactical Javascript implementation（ポルトガル語）-  National Institute of Standards and Technology page on Bresenham's algorithm-  Calcomp 563 Incremental Plotter Information-  3D extension-  Bresenham 2D, 3D up to 6D-  Bresenham Algorithm in several programming languages-  The Beauty of Bresenham's Algorithm – 直線、円、楕円、ベジェ曲線をプロットする単純な実装例