1234567891011121314151617181920 |
- /*
- JavaScript implementation of
- Algorithm for Automatically Fitting Digitized Curves
- by Philip J. Schneider
- "Graphics Gems", Academic Press, 1990
- The MIT License (MIT)
- https://github.com/soswow/fit-curves
- */
- (function(y,w){if("function"===typeof define&&define.amd)define(["module"],w);else if("undefined"!==typeof exports)w(module);else{var v={exports:{}};w(v);y.fitCurve=v.exports}})(this,function(y){function w(a,l){if(!(a instanceof l))throw new TypeError("Cannot call a class as a function");}function v(a,l,b,d,f){var t;if(2===a.length){d=c.vectorLen(c.subtract(a[0],a[1]))/3;var e=[a[0],c.addArrays(a[0],c.mulItems(l,d)),c.addArrays(a[1],c.mulItems(b,d)),a[1]];return[e]}var h=B(a);var k=A(a,h,h,l,b,f);
- e=k[0];var m=k[1];k=k[2];if(0===m||m<d)return[e];if(m<d*d){var q=h;var p=m;var u=k;for(t=0;20>t;t++){q=C(e,a,q);k=A(a,h,q,l,b,f);e=k[0];m=k[1];k=k[2];if(m<d)return[e];if(k===u&&(p=m/p,.9999<p&&1.0001>p))break;p=m;u=k}}e=[];h=c.subtract(a[k-1],a[k+1]);h.every(function(a){return 0===a})&&(h=c.subtract(a[k-1],a[k]),m=[-h[1],h[0]],h[0]=m[0],h[1]=m[1]);h=c.normalize(h);m=c.mulItems(h,-1);e=e.concat(v(a.slice(0,k+1),l,h,d,f));return e=e.concat(v(a.slice(k),m,b,d,f))}function A(a,l,b,d,f,t){var e,h=a[0],
- k=a[a.length-1];var m=[h,null,null,k];var q=c.zeros_Xx2x2(b.length);var p=0;for(e=b.length;p<e;p++){var u=b[p];var g=1-u;var r=q[p];r[0]=c.mulItems(d,3*u*g*g);r[1]=c.mulItems(f,3*g*u*u)}g=[[0,0],[0,0]];var n=[0,0];p=0;for(e=a.length;p<e;p++)u=b[p],r=q[p],g[0][0]+=c.dot(r[0],r[0]),g[0][1]+=c.dot(r[0],r[1]),g[1][0]+=c.dot(r[0],r[1]),g[1][1]+=c.dot(r[1],r[1]),u=c.subtract(a[p],x.q([h,h,k,k],u)),n[0]+=c.dot(r[0],u),n[1]+=c.dot(r[1],u);b=g[0][0]*g[1][1]-g[1][0]*g[0][1];q=g[0][0]*n[1]-g[1][0]*n[0];g=n[0]*
- g[1][1]-n[1]*g[0][1];g=0===b?0:g/b;n=0===b?0:q/b;q=c.vectorLen(c.subtract(h,k));b=1E-6*q;g<b||n<b?(m[1]=c.addArrays(h,c.mulItems(d,q/3)),m[2]=c.addArrays(k,c.mulItems(f,q/3))):(m[1]=c.addArrays(h,c.mulItems(d,g)),m[2]=c.addArrays(k,c.mulItems(f,n)));d=0;f=Math.floor(a.length/2);g=D(m,10);h=0;for(k=a.length;h<k;h++){n=a[h];q=void 0;b=l[h];if(0>b)b=0;else if(1<b)b=1;else{for(e=1;10>=e;e++)if(b<=g[e]){q=(e-1)/10;r=e/10;p=g[e-1];e=g[e];q=(b-p)/(e-p)*(r-q)+q;break}b=q}n=c.subtract(x.q(m,b),n);n=n[0]*n[0]+
- n[1]*n[1];n>d&&(d=n,f=h)}f=[d,f];d=f[0];f=f[1];t&&t({bez:m,points:a,params:l,maxErr:d,maxPoint:f});return[m,d,f]}function C(a,l,b){return b.map(function(b,f){f=l[f];var d=c.subtract(x.q(a,b),f),e=x.qprime(a,b);f=c.mulMatrix(d,e);d=c.sum(c.squareItems(e))+2*c.mulMatrix(d,x.qprimeprime(a,b));return 0===d?b:b-f/d})}function B(a){var l=[],b,d,f;a.forEach(function(a,e){b=e?d+c.vectorLen(c.subtract(a,f)):0;l.push(b);d=b;f=a});return l=l.map(function(b){return b/d})}function z(a,l){return c.normalize(c.subtract(a,
- l))}var D=function(a,l){for(var b,d=[0],f=a[0],t=0,e=1;e<=l;e++)b=x.q(a,e/l),t+=c.vectorLen(c.subtract(b,f)),d.push(t),f=b;return d=d.map(function(b){return b/t})},c=function(){function a(){w(this,a)}a.zeros_Xx2x2=function(a){for(var b=[];a--;)b.push([0,0]);return b};a.mulItems=function(a,b){return a.map(function(a){return a*b})};a.mulMatrix=function(a,b){return a.reduce(function(a,c,l){return a+c*b[l]},0)};a.subtract=function(a,b){return a.map(function(a,c){return a-b[c]})};a.addArrays=function(a,
- b){return a.map(function(a,c){return a+b[c]})};a.addItems=function(a,b){return a.map(function(a){return a+b})};a.sum=function(a){return a.reduce(function(a,c){return a+c})};a.dot=function(c,b){return a.mulMatrix(c,b)};a.vectorLen=function(a){return Math.hypot.apply(Math,a)};a.divItems=function(a,b){return a.map(function(a){return a/b})};a.squareItems=function(a){return a.map(function(a){return a*a})};a.normalize=function(a){return this.divItems(a,this.vectorLen(a))};return a}(),x=function(){function a(){w(this,
- a)}a.q=function(a,b){var d=1-b,l=c.mulItems(a[0],d*d*d),t=c.mulItems(a[1],3*d*d*b);d=c.mulItems(a[2],3*d*b*b);a=c.mulItems(a[3],b*b*b);return c.addArrays(c.addArrays(l,t),c.addArrays(d,a))};a.qprime=function(a,b){var d=1-b,l=c.mulItems(c.subtract(a[1],a[0]),3*d*d);d=c.mulItems(c.subtract(a[2],a[1]),6*d*b);a=c.mulItems(c.subtract(a[3],a[2]),3*b*b);return c.addArrays(c.addArrays(l,d),a)};a.qprimeprime=function(a,b){return c.addArrays(c.mulItems(c.addArrays(c.subtract(a[2],c.mulItems(a[1],2)),a[0]),
- 6*(1-b)),c.mulItems(c.addArrays(c.subtract(a[3],c.mulItems(a[2],2)),a[1]),6*b))};return a}();y.exports=function(a,c,b){if(!Array.isArray(a))throw new TypeError("First argument should be an array");a.forEach(function(b){if(!Array.isArray(b)||b.some(function(a){return"number"!==typeof a})||b.length!==a[0].length)throw Error("Each point should be an array of numbers. Each point should have the same amount of numbers.");});a=a.filter(function(b,c){return 0===c||!b.every(function(b,d){return b===a[c-1][d]})});
- if(2>a.length)return[];var d=a.length,f=z(a[1],a[0]);d=z(a[d-2],a[d-1]);return v(a,f,d,c,b)};y.exports.fitCubic=v;y.exports.createTangent=z});
|