等高線を描く
基盤地図情報を使うと画像が公開できないので、普通の画像のRGBを標高値として等高線を描きます。
アルゴリズムが合ってんだか間違ってんだか分からん。(間違ってたのでコード修正しました)
簡単なアルゴリズムでは、画像を三角形に分割してその中で線を引いていきます。
使用
// 点 function Point3D(x, y, z){ if(!x) x = 0; if(!y) y = 0; if(!z) z = 0; this.x = x; this.y = y; this.z = z; } /** * 分割して線を引かせる部分 * @boxInterval 三角形の大きさ * @conInterval 等高線を引く間隔 */ ImageProcessing.prototype.drawContour = function(boxInterval, conInterval){ var ps = []; var _x = 0, _y = 0; var canvas = this.clone().clear(); // 等高線を描くCanvas for(var x = 0; x < this.canvas.width; x += boxInterval){ for(var y = 0; y < this.canvas.height; y += boxInterval){ _x = x + boxInterval; _y = y + boxInterval; if(_x >= this.canvas.width) _x = this.canvas.width - 1; if(_y >= this.canvas.height) _y = this.canvas.height - 1; ps[0] = new Point3D(x, y, this.getPixel(x, y).g); ps[1] = new Point3D(x, _y, this.getPixel(x, _y).g); ps[2] = new Point3D(_x, y, this.getPixel(_x, y).g); this.drawContourLine(canvas, ps, conInterval); // 修正 ps[0] = new Point3D(_x, _y, this.getPixel(_x, _y).g); this.drawContourLine(canvas, ps, conInterval); // 間違い /* if(x - boxInterval < 0){ ps[2] = new Point3D(x - boxInterval, _y, this.getPixel(x - boxInterval, _y).g); this.drawContourLine(canvas, ps, conInterval); }*/ } } return canvas; };
あとは線を引くだけです。簡単ですね。
/** * 実際に線を引く部分 * @process 線を引くCanvas * @points 三角形の点たち * @interval 等高線の間隔 */ ImageProcessing.prototype.drawContourLine = function(process, points, interval){ // 点の中の最大と最小の標高値をintervalで丸めてます var contourL = parseInt(Math.min.apply(null, points.map(function(p){ return p.z; })) / interval) * interval; var contourH = parseInt(Math.max.apply(null, points.map(function(p){ return p.z; })) / interval) * interval; var flags = []; var ratio = 0; var x1 = 0, y1 = 0; var x2 = 0, y2 = 0; var drawLine = function(x1, y1, x2, y2){ process.context.beginPath(); process.context.moveTo(x1, y1); process.context.lineTo(x2, y2); process.context.closePath(); process.context.stroke(); }; for(var h = contourL; h <= contourH; h += interval){ // どこに線を引くか調べてます flags = [ (points[0].z <= h && h <= points[1].z) || (points[1].z <= h && h <= points[0].z), (points[1].z <= h && h <= points[2].z) || (points[2].z <= h && h <= points[1].z), (points[2].z <= h && h <= points[0].z) || (points[0].z <= h && h <= points[2].z) ]; // 線引いてます if(flags[0] && flags[1] && points[1].z != points[0].z && points[2].z != points[1].z){ ratio = (h - points[0].z) / (points[1].z - points[0].z); x1 = ratio * (points[1].x - points[0].x) + points[0].x; y1 = ratio * (points[1].y - points[0].y) + points[0].y; ratio = (h - points[1].z) / (points[2].z - points[1].z); x2 = ratio * (points[2].x - points[1].x) + points[1].x; y2 = ratio * (points[2].y - points[1].y) + points[1].y; drawLine(x1, y1, x2, y2); } if(flags[1] && flags[2] && points[2].z != points[1].z && points[2].z != points[0].z){ ratio = (h - points[1].z) / (points[2].z - points[1].z); x1 = ratio * (points[2].x - points[1].x) + points[1].x; y1 = ratio * (points[2].y - points[1].y) + points[1].y; ratio = (h - points[2].z) / (points[0].z - points[2].z); x2 = ratio * (points[0].x - points[2].x) + points[2].x; y2 = ratio * (points[0].y - points[2].y) + points[2].y; drawLine(x1, y1, x2, y2); } if(flags[2] && flags[0] && points[0].z != points[2].z && points[1].z != points[0].z){ ratio = (h - points[2].z) / (points[0].z - points[2].z); x1 = ratio * (points[0].x - points[2].x) + points[2].x; y1 = ratio * (points[0].y - points[2].y) + points[2].y; ratio = (h - points[0].z) / (points[1].z - points[0].z); x2 = ratio * (points[1].x - points[0].x) + points[0].x; y2 = ratio * (points[1].y - points[0].y) + points[0].y; drawLine(x1, y1, x2, y2); } } };
三角形の大きさが大きいほど大雑把な感じです。楽しいですね。
分割サイズ | 図 |
---|---|
1 | |
5 | |
10 |
等高線を引く間隔を変えると線の数が変わります。三角形って感じですね。
間隔 | 図 |
---|---|
16 | |
32 | |
64 |