地図/基礎/Canvas と数学

線のラスタライズ — Bresenham

格子に直線を引きたい。始点と終点を結ぶ直線の式は y = 始点 + 傾き × (x - 始点) で、x を一つ進めるたびに y を傾きぶん足す。けれど傾きは割り算で出る小数で、各セルでは Math.round の丸めが要る。格子の各マスを整数の足し引きだけで決めたい。

Bresenham のアルゴリズムは、直線を引くのに割り算も浮動小数も使わない。傾きの代わりに整数の誤差項 err を一つ持ち、x を一歩進めるごとに errdy を足す。err が閾値を越えたら y を一歩進め、errdx ぶん戻す。理想の直線から今のマスがどれだけ離れているかを err が整数で覚えていて、離れすぎる前に縦へ寄せる。Jack Bresenham が 1962 年に IBM のプロッタ制御のために考案した。

始点と終点を格子座標で決めて、err を足し引きしながら一マスずつ進める。dx は横の距離、dy は縦の距離を負にしたもの。e2 = 2 * errdydx と比べて、越えた向きへ一歩動かす。塗るのは面なので cellW = w / ncellH = h / n でマスを埋める。終点に着いたら別の終点で引き直す。

毎フレーム一マスずつ塗られて、始点から終点へ階段状に伸びる。err が横へ進むたびに減り、dx を越えると縦に一歩寄って dy ぶん戻る。傾きが緩いと横ばかり進んで縦の段が間遠になり、急だと縦の段が詰まる。割り算は一度も出ず、足し引きと比較だけでマスが決まる。終点へ届いたら新しい終点で引き直す。

中心から複数の終点へ同じ手順で引くと放射状になる。一本ぶんの xyerr を線ごとに別々に持って、各フレームで全部を一歩ずつ進める。終点は角度 acossin で円周に並べて決める。sin(phase * 1.7 + i) を角度に混ぜて散らし、全本が着いたら phase を進めて引き直す。

同じ誤差項の足し引きが線の本数ぶん並走して、中心から放射状に伸びる。半透明の paper を毎フレーム上から塗っているので、伸びた跡が尾を引いて薄れる。終点の角度を cossin で円周に置くだけで、上向きも斜めも同じ手順で引ける。spokes を増やすと線が密に、radius を上げると長く伸びる。

横を一歩進めるたびに整数の誤差を足し、閾値を越えたら縦へ一歩寄る——丸めも割り算もない足し引きだけで、格子の上に直線が立つ。