Bスプライン曲線を復習する
滑らかな曲線を描く発生器が欲しくなったので再び考える
最終的な目的は、始点が(0,0)で終点が(1,1)、中に2点で全部で4つ。
高速に動作する。もちろんある程度短いことにこしたことはない。
で基本から。
<!DOCTYPE html> <meta charset="utf-8"> <title>B-spline</title> <body> <canvas width="500" height="500"></canvas> <script> function B_Spline_Generator (point) { var m = point.length; var n = m - 1; return function (t) { var cn, i, j, t0, t1, t2; var x = 0, y = 0; t0 = Math.min (Math.max (0, t), 1) * m - 1; for (i = -2; i < m + 2; i += 1) { cn = ((t1 = Math.abs (t0 - i)) < 1) ? (t2 = 3 * t1 * t1, t1 * t2 - 2 * t2 + 4) / 6 : (t1 < 2) ? (t2 = t1 - 2, t2 * t2 * t2 / -6) : 0; j = Math.min (Math.max (0, i), n); x += point[j][0] * cn; y += point[j][1] * cn; } return {x: x, y: y}; } } //__________________________ (function () { var ps =[[30, 90],[231,147],[63,495],[513,129],[459,492]]; var pointer = B_Spline_Generator (ps); var canvas = document.querySelector ('canvas'); var ctx = canvas.getContext('2d'); var p, x, y; ctx.beginPath (); ctx.strokeStyle = 'rgb(255,0,0)'; for (var i = 0; i <= 1; i += .01) { p = pointer (i); ctx[i ? 'lineTo': 'moveTo'](p.x, p.y); } ctx.stroke (); })(); </script>
気持ち高速にする
<!DOCTYPE html> <meta charset="utf-8"> <title>B-spline</title> <body> <canvas width="500" height="500"></canvas> <script> function B_Spline_Generator (x1, y1, x2, y2) { var p = [[0,0], [x1,y1], [x2,y2], [1,1]]; return function (t) { var cn, i, t0, t1, t2, p0; var x = 0, y = 0; t0 = Math.min (Math.max (0, t), 1) * 3; for (i = -2; i < 6; i += 1) { t1 = Math.abs (t0 - i); if (2 <= t1) continue; cn = (t1 < 1) ? (t2 = 3 * t1 * t1, t1 * t2 - 2 * t2 + 4) / 6 : (t2 = t1 - 2, t2 * t2 * t2 / -6); p0 = p[Math.min (Math.max (0, i), 3)]; x += p0[0] * cn; y += p0[1] * cn; } return {x: x, y: y}; } } //__________________________ (function () { var pointer = B_Spline_Generator (1,0,0,1); var canvas = document.querySelector ('canvas'); var ctx = canvas.getContext('2d'); var p, x, y; ctx.beginPath (); ctx.strokeStyle = 'rgb(255,0,0)'; for (var i = 0; i <= 1; i += .01) { p = pointer (i); ctx[i ? 'lineTo': 'moveTo'](p.x*400, p.y*400); } ctx.stroke (); })(); </script>
2017-4-19 書き直す
<!DOCTYPE html> <meta charset="utf-8"> <title>B-spline</title> <body> <canvas width="500" height="500"></canvas> <script> (function () { var min = Math.min; var max = Math.max; var abs = Math.abs; function Spline (p, m ,n) { this.p = p; this.m = m; this.n = n; } function calc (t) { var cn, i, j, t0, t1, t2; var x = 0, y = 0; var m = this.m; var n = this.n; var p = this.p; t0 = min (max (0, t), 1) * m - 1; for (i = -2; i < m + 2; i += 1) { cn = ((t1 = abs (t0 - i)) < 1) ? (t2 = 3 * t1 * t1, t1 * t2 - 2 * t2 + 4) / 6 : (t1 < 2) ? (t2 = t1 - 2, t2 * t2 * t2 / -6) : 0; j = min (max (0, i), n); x += p[j].x * cn; y += p[j].y * cn; } return {x: x, y: y}; } function create (aryPoint) { var len = aryPoint.length; var obj = new Spline (aryPoint, len, len - 1); return obj; } Spline.create = create; Spline.prototype.calc = calc; this.Spline = Spline; })(); //__________________________ (function () { var ps =[ {x: 30, y: 90}, {x: 231, y: 147}, {x: 63, y: 495}, {x: 513, y: 129}, {x: 459, y: 492} ]; var pointer = Spline.create (ps); var canvas = document.querySelector ('canvas'); var ctx = canvas.getContext('2d'); var p, x, y, i; ctx.beginPath (); ctx.strokeStyle = 'rgb(255,0,0)'; for (i = 0; i <= 1; i += .01) { p = pointer.calc (i); ctx[i ? 'lineTo': 'moveTo'](p.x, p.y); } ctx.stroke (); })(); </script>
2017-4-19 ES6っぽく
<!DOCTYPE html> <meta charset="utf-8"> <title>B-spline</title> <body> <canvas width="500" height="500"></canvas> <script> { class Spline { constructor (ps = []) { this.p = ps; this.m = ps.length; this.n = this.m - 1; } calc (t = 0) { let {min, max, abs} = Math, {p, m, n} = this, x = 0, y = 0, t0 = min (max (0, t), 1) * m - 1; for (let i = -2; i < m + 2; i += 1) { let t1 = abs (t0 - i), t2, j = min (max (0, i), n), cn = t1 < 1 ? (t2 = 3 * t1 * t1, t1 * t2 - 2 * t2 + 4) / 6 : (t1 < 2) ? (t2 = t1 - 2, t2 * t2 * t2 / -6) : 0; x += p[j].x * cn; y += p[j].y * cn; } return {x: x, y: y}; } } this.Spline = Spline; } //__________________________ { let ps =[ {x: 30, y: 90}, {x: 231, y: 147}, {x: 63, y: 495}, {x: 513, y: 129}, {x: 459, y: 492} ], pointer = new Spline (ps), ctx = document.querySelector ('canvas').getContext('2d'); ctx.beginPath (); ctx.strokeStyle = 'rgb(255,0,0)'; for (let i = 0; i <= 1; i += .01) { let {x, y} = pointer.calc (i); ctx[i ? 'lineTo': 'moveTo'](x, y); } ctx.stroke (); } </script>