A Pen by Andrew Hung on CodePen.
Created
March 9, 2017 22:46
-
-
Save anonymous/ace6ed8cc3130bcdd261ba9cd27b8ab9 to your computer and use it in GitHub Desktop.
Catmull-Rom Spline
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <canvas id="canv" height="3000" width="3000"></canvas> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const tau = 1; | |
| function matrix(...rows) { | |
| this.rows = rows; | |
| this.cols = []; | |
| for (let i = 0; i < rows[0].length; i++) { | |
| let col = []; | |
| for (let j = 0; j < this.rows.length; j++) { | |
| col.push(this.rows[j][i]); | |
| } | |
| this.cols.push(col); | |
| } | |
| } | |
| function dot(v1, v2) { | |
| var sum = 0; | |
| for (let i = 0; i < v1.length; i++) { | |
| sum += v1[i] * v2[i]; | |
| } | |
| return sum; | |
| } | |
| matrix.prototype.print = function() { | |
| for (let i = 0; i < this.rows.length; i++) { | |
| var str = "["; | |
| for (let j = 0; j < this.cols.length; j++) { | |
| str += this.rows[i][j]; | |
| if (j < this.cols.length - 1) str += " "; | |
| } | |
| str += "]"; | |
| console.log(str); | |
| } | |
| } | |
| matrix.prototype.mul = function(other) { | |
| var result = []; | |
| for (let i = 0; i < this.rows.length; i++) { | |
| result.push([]); | |
| for (let j = 0; j < other.cols.length; j++) { | |
| result[i][j] = dot(this.rows[i], other.cols[j]); | |
| } | |
| } | |
| return new matrix(...result); | |
| } | |
| matrix.prototype.scalarMul = function(scalar) { | |
| for (let i = 0; i < this.rows.length; i++) { | |
| for (let j = 0; j < this.cols.length; j++) { | |
| this.rows[i][j] = this.rows[i][j] * scalar; | |
| } | |
| } | |
| } | |
| var catmullRomMatrix = new matrix([0, 2, 0, 0], [-tau, 0, tau, 0], [2*tau, tau-6, -2*(tau-3), -tau], [-tau, 4-tau, tau-4, tau]); | |
| catmullRomMatrix.scalarMul(.5); | |
| function spline(controlPoints){ | |
| this.points = controlPoints; | |
| this.functionCache = []; | |
| for (i = 0; i < this.points.length - 3; i++) { | |
| this.functionCache.push([]); | |
| } | |
| } | |
| spline.prototype.getHermiteFunction = function(p, index) { | |
| if (this.functionCache[p][index] == undefined) { | |
| this.functionCache[p][index] = catmullRomMatrix.mul(new matrix([this.points[p][index]], | |
| [this.points[p + 1][index]], [this.points[p+2][index]], [this.points[p+3][index]])); | |
| } | |
| return this.functionCache[p][index]; | |
| } | |
| spline.prototype.evaluate = function(rawT) { | |
| var i = Math.floor(rawT); | |
| var t = rawT % 1; | |
| if (i + 3 >= this.points.length) return false; | |
| var cx = this.getHermiteFunction(i, 0); | |
| var cy = this.getHermiteFunction(i, 1); | |
| return [cx.rows[0][0] + t * cx.rows[1][0] + t * t * cx.rows[2][0] + t * t * t * cx.rows[3][0], | |
| cy.rows[0][0] + t * cy.rows[1][0] + t * t * cy.rows[2][0] + t * t * t * cy.rows[3][0]]; | |
| } | |
| var initialTime = Date.now(); | |
| var canv = document.getElementById("canv"); | |
| var ctx = canv.getContext("2d"); | |
| var ctrlPoints = [[30, 60], [70, 130], [110, 50], [150, 150], [200, 220], [300, 100], [450, 200], [520, 100]]; | |
| var spline = new spline(ctrlPoints); | |
| function draw() { | |
| let t = Date.now() - initialTime; | |
| t /= 500; | |
| ctx.clearRect(0, 0, canv.width, canv.height); | |
| renderSpline(); | |
| ctx.fillStyle = "rgb(200, 0, 1)"; | |
| ctrlPoints.forEach(function(point){ | |
| ctx.beginPath(); | |
| ctx.moveTo(point[0], point[1]); | |
| ctx.arc(point[0], point[1], 5, 0, Math.PI * 2, true); | |
| ctx.fill(); | |
| }); | |
| let splinePoint = spline.evaluate(t); | |
| if (splinePoint == false) { | |
| initialTime = Date.now(); | |
| } else { | |
| ctx.fillStyle = "rgb(0, 200, 0)"; | |
| ctx.beginPath(); | |
| ctx.moveTo(splinePoint[0], splinePoint[1]); | |
| ctx.arc(splinePoint[0], splinePoint[1], 5, 0, Math.PI * 2, true); | |
| ctx.fill(); | |
| } | |
| window.requestAnimationFrame(draw); | |
| } | |
| function renderSpline() { | |
| let t = 0; | |
| while (t < ctrlPoints.length) { | |
| let splinePoint = spline.evaluate(t); | |
| ctx.fillStyle = "rgb(50, 50, 200)"; | |
| ctx.beginPath(); | |
| ctx.moveTo(splinePoint[0], splinePoint[1]); | |
| ctx.arc(splinePoint[0], splinePoint[1], 1, 0, Math.PI * 2, true); | |
| ctx.fill(); | |
| t += .01; | |
| } | |
| } | |
| renderSpline(); | |
| draw(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| body{ | |
| margin: 0; | |
| width:100%; | |
| padding: 0; | |
| overflow: hidden; | |
| background:hsla(0,5%,10%,1); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment