2.2. 線分を描く

3Dの基本的な知識を理解したくて、『３次元CGの基礎と応用［新訂版］（ http://goo.gl/GKoQ4y ）』という書籍を購入しました。薄くて読みやすそうな本なのですがサンプルソースがないので、勉強がてらサンプルを作りながら読み進めようと思います。誰でもすぐに追試ができるよう、HTML + Javascriptでサンプルを作っていきます。

完全なサンプルはこちら
https://github.com/nakaken0629/3dstudy

# 2.2. 線分を描く

この節では、数学的な線分の定義の説明をした後に、これを掛け算や割り算、実数などを使わずに描画する「ブレゼンハムのアルゴリズム」について説明しています。書籍内では、0 < dx/dy < 1 の条件のみについて説明されていますが、サンプルコードではその他の条件のときも正しく描画できるようにしています。

![session2_2.png](https://qiita-image-store.s3.amazonaws.com/0/75307/e4952b09-0564-da24-22b4-473a317da8bf.png "session2_2.png")

## サンプルコード

```js:session2_2.htmlより
/* 共通処理 */

var canvas;
var ctx;

window.onload = function() {
    canvas = document.getElementById("myCanvas");
    ctx = canvas.getContext("2d");
    main();
};

var createRgb = function(red, green, blue) {
    return "#"
        + ("0" + red.toString(16)).substr(-2)
        + ("0" + green.toString(16)).substr(-2)
        + ("0" + blue.toString(16)).substr(-2)
    ;
};

var getRandomInt = function(min, max) {
      return Math.floor( Math.random() * (max - min + 1) ) + min;
};

/* 個別処理 */

var main = function() {
    for(var i = 0; i < 100; i++) {
        x1 = getRandomInt(0, 319);
        y1 = getRandomInt(0, 199);
        x2 = getRandomInt(0, 319);
        y2 = getRandomInt(0, 199);
        red = getRandomInt(0, 255);
        green = getRandomInt(0, 255);
        blue = getRandomInt(0, 255);
        line(x1, y1, x2, y2, createRgb(red, green, blue));
    }
}


var pset = function(x, y, rgb) {
    /* 1pxでは見づらいため、2pxとしている */
    ctx.fillStyle = rgb;
    ctx.fillRect(x * 2, y * 2, 2, 2);
};

var line = function(x1, y1, x2, y2, rgb) {
    if (Math.abs(x2 - x1) > Math.abs(y2 - y1)) {
        if (x1 > x2) {
            x2 = [x1, x1 = x2][0];  /* swap x1 and x2 */
            y2 = [y1, y1 = y2][0];  /* swap y1 and y2 */
        }
        if (y1 < y2) {
            /* Xを1ずつ増やしてYが増加する線分 */
            var dx = x2 - x1;
            var dy = y2 - y1;
            var d = 2 * dy - dx;
            pset(x1, y1, rgb);
            var y = y1;
            for(var x = x1 + 1; x <= x2; x++) {
                if (d >= 0) {
                    y++;
                    d += 2 * (dy - dx);
                } else {
                    d += 2 * dy;
                }
                pset(x, y , rgb);
            }
        } else {
            /* Xを1ずつ増やしてYが減少する線分 */
            var dx = x2 - x1;
            var dy = -(y2 - y1);
            var d = 2 * dy - dx;
            pset(x1, y1, rgb);
            var y = y1;
            for(var x = x1 + 1; x <= x2; x++) {
                if (d >= 0) {
                    y--;
                    d += 2 * (dy - dx);
                } else {
                    d += 2 * dy;
                }
                pset(x, y , rgb);
            }
        }
    } else {
        if (y1 > y2) {
            y2 = [y1, y1 = y2][0];  /* swap y1 and y2 */
            x2 = [x1, x1 = x2][0];  /* swap x1 and x2 */
        }
        if (x1 < x2) {
            /* Yを1ずつ増やしてXが増加する線分 */
            var dy = y2 - y1;
            var dx = x2 - x1;
            var d = 2 * dx - dy;
            pset(x1, y1, rgb);
            var x = x1;
            for(var y = y1 + 1; y <= y2; y++) {
                if (d >= 0) {
                    x++;
                    d += 2 * (dx - dy);
                } else {
                    d += 2 * dx;
                }
                pset(x, y , rgb);
            }
        } else {
            /* Yを1ずつ増やしてXが減少する線分 */
            var dy = y2 - y1;
            var dx = -(x2 - x1);
            var d = 2 * dx - dy;
            pset(x1, y1, rgb);
            var x = x1;
            for(var y = y1 + 1; y <= y2; y++) {
                if (d >= 0) {
                    x--;
                    d += 2 * (dx - dy);
                } else {
                    d += 2 * dx;
                }
                pset(x, y , rgb);
            }
        }
    }
};
```