-
-
Save collarbone/43f3234ee1dd42e2ed6976d33df7b937 to your computer and use it in GitHub Desktop.
Catmull Rom Fitting Algorithm in Javascript through a series of X/Y Points
This file contains 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
/** | |
* Interpolates a Catmull-Rom Spline through a series of x/y points | |
* Converts the CR Spline to Cubic Beziers for use with SVG items | |
* | |
* If 'alpha' is 0.5 then the 'Centripetal' variant is used | |
* If 'alpha' is 1 then the 'Chordal' variant is used | |
* | |
* | |
* @param {Array} data - Array of points, each point in object literal holding x/y values | |
* @return {String} d - SVG string with cubic bezier curves representing the Catmull-Rom Spline | |
*/ | |
var catmullRomFitting = function (data,alpha) { | |
if (alpha == 0 || alpha === undefined) { | |
return false; | |
} else { | |
var p0, p1, p2, p3, bp1, bp2, d1, d2, d3, A, B, N, M; | |
var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA; | |
var d = Math.round(data[0].x) + ',' + Math.round(data[0].y) + ' '; | |
var length = data.length; | |
for (var i = 0; i < length - 1; i++) { | |
p0 = i == 0 ? data[0] : data[i - 1]; | |
p1 = data[i]; | |
p2 = data[i + 1]; | |
p3 = i + 2 < length ? data[i + 2] : p2; | |
d1 = Math.sqrt(Math.pow(p0.x - p1.x, 2) + Math.pow(p0.y - p1.y, 2)); | |
d2 = Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)); | |
d3 = Math.sqrt(Math.pow(p2.x - p3.x, 2) + Math.pow(p2.y - p3.y, 2)); | |
// Catmull-Rom to Cubic Bezier conversion matrix | |
// A = 2d1^2a + 3d1^a * d2^a + d3^2a | |
// B = 2d3^2a + 3d3^a * d2^a + d2^2a | |
// [ 0 1 0 0 ] | |
// [ -d2^2a /N A/N d1^2a /N 0 ] | |
// [ 0 d3^2a /M B/M -d2^2a /M ] | |
// [ 0 0 1 0 ] | |
d3powA = Math.pow(d3, alpha); | |
d3pow2A = Math.pow(d3, 2 * alpha); | |
d2powA = Math.pow(d2, alpha); | |
d2pow2A = Math.pow(d2, 2 * alpha); | |
d1powA = Math.pow(d1, alpha); | |
d1pow2A = Math.pow(d1, 2 * alpha); | |
A = 2 * d1pow2A + 3 * d1powA * d2powA + d2pow2A; | |
B = 2 * d3pow2A + 3 * d3powA * d2powA + d2pow2A; | |
N = 3 * d1powA * (d1powA + d2powA); | |
if (N > 0) { | |
N = 1 / N; | |
} | |
M = 3 * d3powA * (d3powA + d2powA); | |
if (M > 0) { | |
M = 1 / M; | |
} | |
bp1 = { x: (-d2pow2A * p0.x + A * p1.x + d1pow2A * p2.x) * N, | |
y: (-d2pow2A * p0.y + A * p1.y + d1pow2A * p2.y) * N }; | |
bp2 = { x: (d3pow2A * p1.x + B * p2.x - d2pow2A * p3.x) * M, | |
y: (d3pow2A * p1.y + B * p2.y - d2pow2A * p3.y) * M }; | |
if (bp1.x == 0 && bp1.y == 0) { | |
bp1 = p1; | |
} | |
if (bp2.x == 0 && bp2.y == 0) { | |
bp2 = p2; | |
} | |
d += 'C' + bp1.x + ',' + bp1.y + ' ' + bp2.x + ',' + bp2.y + ' ' + p2.x + ',' + p2.y + ' '; | |
} | |
return d; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment