Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Sketchometry.activity/js/sk.js
blob: 32363746f3baca32784efd417d0699cccf5caf9d (plain)
1
function Point(t,e){this.X=t;this.Y=e}function Rectangle(t,e,n,r){this.X=t;this.Y=e;this.Width=n;this.Height=r}function Template(t,e,n){this.Name=t;this.Points=Resample(n,NumPoints);var r=IndicativeAngle(this.Points);this.Points=RotateBy(this.Points,-r);this.Points=ScaleDimTo(this.Points,SquareSize,OneDThreshold);if(e)this.Points=RotateBy(this.Points,+r);this.Points=TranslateTo(this.Points,Origin);this.StartUnitVector=CalcStartUnitVector(this.Points,StartAngleIndex);this.Vector=Vectorize(this.Points,e)}function Multistroke(t,e,n){this.Name=t;this.NumStrokes=n.length;var r=new Array;for(var i=0;i<n.length;i++)r[i]=i;var a=new Array;HeapPermute(n.length,r,a);this.Templates=new Array;var o=MakeUnistrokes(n,a);for(var s=0;s<o.length;s++)this.Templates[s]=new Template(t,e,o[s])}function Result(t,e){this.Name=t;this.Score=e}var NumMultistrokes=16;var NumPoints=96;var SquareSize=250;var OneDThreshold=.25;var Origin=new Point(0,0);var Diagonal=Math.sqrt(SquareSize*SquareSize+SquareSize*SquareSize);var HalfDiagonal=.5*Diagonal;var AngleRange=Deg2Rad(45);var AnglePrecision=Deg2Rad(2);var Phi=.5*(-1+Math.sqrt(5));var StartAngleIndex=NumPoints/8;var AngleSimilarityThreshold=Deg2Rad(30);function NDollarRecognizer(t){this.Multistrokes=new Array;this.Recognize=function(t,e,n,r,i,a,o){var s;if(i)s=JxgCombineStrokes(t);else s=CombineStrokes(t);s=Resample(s,NumPoints);var h=IndicativeAngle(s);s=RotateBy(s,-h);s=ScaleDimTo(s,SquareSize,OneDThreshold);if(e)s=RotateBy(s,+h);s=TranslateTo(s,Origin);var l=CalcStartUnitVector(s,StartAngleIndex);var u=Vectorize(s,e);var v=+Infinity;var g=-1;for(var f=0;f<this.Multistrokes.length;f++){if(!n||t.length==this.Multistrokes[f].NumStrokes){for(var c=0;c<this.Multistrokes[f].Templates.length;c++){var M,P;if(typeof a!=="undefined"){P=false;for(M=0;M<a.length;M++){if(this.Multistrokes[f].Name===a[M]){P=true;break}}if(P)continue}if(typeof o!=="undefined"){P=true;for(M=0;M<o.length;M++){if(this.Multistrokes[f].Name===o[M]){P=false;break}}if(P)continue}if(AngleBetweenUnitVectors(l,this.Multistrokes[f].Templates[c].StartUnitVector)<=AngleSimilarityThreshold){var m;if(r){m=OptimalCosineDistance(this.Multistrokes[f].Templates[c].Vector,u)}else{m=DistanceAtBestAngle(s,this.Multistrokes[f].Templates[c],-AngleRange,+AngleRange,AnglePrecision)}if(m<v){v=m;g=f}}}}}return g==-1?new Result("No match.",0):new Result(this.Multistrokes[g].Name,r?1/v:1-v/HalfDiagonal)};this.AddMultistroke=function(t,e,n){this.Multistrokes[this.Multistrokes.length]=new Multistroke(t,e,n);var r=0;for(var i=0;i<this.Multistrokes.length;i++){if(this.Multistrokes[i].Name==t)r++}return r};this.DeleteUserMultistrokes=function(){this.Multistrokes.length=NumMultistrokes;return NumMultistrokes}}function HeapPermute(t,e,n){if(t==1){n[n.length]=e.slice()}else{for(var r=0;r<t;r++){HeapPermute(t-1,e,n);if(t%2==1){var i=e[0];e[0]=e[t-1];e[t-1]=i}else{var i=e[r];e[r]=e[t-1];e[t-1]=i}}}}function MakeUnistrokes(t,e){var n=new Array;for(var r=0;r<e.length;r++){for(var i=0;i<Math.pow(2,e[r].length);i++){var a=new Array;for(var o=0;o<e[r].length;o++){var s;if((i>>o&1)==1){s=t[e[r][o]].slice().reverse()}else{s=t[e[r][o]].slice()}for(var h=0;h<s.length;h++){a[a.length]=s[h]}}n[n.length]=a}}return n}function CombineStrokes(t){var e=new Array;for(var n=0;n<t.length;n++){for(var r=0;r<t[n].length;r++){e[e.length]=new Point(t[n][r].X,t[n][r].Y)}}return e}function JxgCombineStrokes(t){var e=[];for(var n=0;n<t.length;n++)for(var r=0;r<t[n].length;r++)e[e.length]=new Point(t[n][r].scrCoords[1],t[n][r].scrCoords[2]);return e}function Resample(t,e){var n=PathLength(t)/(e-1);var r=0;var i=new Array(t[0]);for(var a=1;a<t.length;a++){var o=Distance(t[a-1],t[a]);if(r+o>=n){var s=t[a-1].X+(n-r)/o*(t[a].X-t[a-1].X);var h=t[a-1].Y+(n-r)/o*(t[a].Y-t[a-1].Y);var l=new Point(s,h);i[i.length]=l;t.splice(a,0,l);r=0}else r+=o}if(i.length==e-1){i[i.length]=new Point(t[t.length-1].X,t[t.length-1].Y)}return i}function IndicativeAngle(t){var e=Centroid(t);return Math.atan2(e.Y-t[0].Y,e.X-t[0].X)}function RotateBy(t,e){var n=Centroid(t);var r=Math.cos(e);var i=Math.sin(e);var a=new Array;for(var o=0;o<t.length;o++){var s=(t[o].X-n.X)*r-(t[o].Y-n.Y)*i+n.X;var h=(t[o].X-n.X)*i+(t[o].Y-n.Y)*r+n.Y;a[a.length]=new Point(s,h)}return a}function ScaleDimTo(t,e,n){var r=BoundingBox(t);var i=Math.min(r.Width/r.Height,r.Height/r.Width)<=n;var a=new Array;for(var o=0;o<t.length;o++){var s=i?t[o].X*(e/Math.max(r.Width,r.Height)):t[o].X*(e/r.Width);var h=i?t[o].Y*(e/Math.max(r.Width,r.Height)):t[o].Y*(e/r.Height);a[a.length]=new Point(s,h)}return a}function TranslateTo(t,e){var n=Centroid(t);var r=new Array;for(var i=0;i<t.length;i++){var a=t[i].X+e.X-n.X;var o=t[i].Y+e.Y-n.Y;r[r.length]=new Point(a,o)}return r}function Vectorize(t,e){var n;var r=1;var i=0;if(e){var a=Math.atan2(t[0].Y,t[0].X);var o=Math.PI/4*Math.floor((a+Math.PI/8)/(Math.PI/4));r=Math.cos(o-a);i=Math.sin(o-a)}var s=0;var h=new Array;for(n=0;n<t.length;n++){var l=t[n].X*r-t[n].Y*i;var u=t[n].Y*r+t[n].X*i;h[h.length]=l;h[h.length]=u;s+=l*l+u*u}var v=Math.sqrt(s);for(n=0;n<h.length;n++)h[n]/=v;return h}function OptimalCosineDistance(t,e){var n=0;var r=0;for(var i=0;i<t.length;i+=2){n+=t[i]*e[i]+t[i+1]*e[i+1];r+=t[i]*e[i+1]-t[i+1]*e[i]}var a=Math.atan(r/n);return Math.acos(n*Math.cos(a)+r*Math.sin(a))}function DistanceAtBestAngle(t,e,n,r,i){var a=Phi*n+(1-Phi)*r;var o=DistanceAtAngle(t,e,a);var s=(1-Phi)*n+Phi*r;var h=DistanceAtAngle(t,e,s);while(Math.abs(r-n)>i){if(o<h){r=s;s=a;h=o;a=Phi*n+(1-Phi)*r;o=DistanceAtAngle(t,e,a)}else{n=a;a=s;o=h;s=(1-Phi)*n+Phi*r;h=DistanceAtAngle(t,e,s)}}return Math.min(o,h)}function DistanceAtAngle(t,e,n){var r=RotateBy(t,n);return PathDistance(r,e.Points)}function Centroid(t){var e=0,n=0;for(var r=0;r<t.length;r++){e+=t[r].X;n+=t[r].Y}e/=t.length;n/=t.length;return new Point(e,n)}function BoundingBox(t){var e=+Infinity,n=-Infinity,r=+Infinity,i=-Infinity;for(var a=0;a<t.length;a++){if(t[a].X<e)e=t[a].X;if(t[a].X>n)n=t[a].X;if(t[a].Y<r)r=t[a].Y;if(t[a].Y>i)i=t[a].Y}return new Rectangle(e,r,n-e,i-r)}function PathDistance(t,e){var n=0;for(var r=0;r<t.length;r++)n+=Distance(t[r],e[r]);return n/t.length}function PathLength(t){var e=0;for(var n=1;n<t.length;n++)e+=Distance(t[n-1],t[n]);return e}function Distance(t,e){var n=e.X-t.X;var r=e.Y-t.Y;return Math.sqrt(n*n+r*r)}function CalcStartUnitVector(t,e){var n=new Point(t[e].X-t[0].X,t[e].Y-t[0].Y);var r=Math.sqrt(n.X*n.X+n.Y*n.Y);return new Point(n.X/r,n.Y/r)}function AngleBetweenUnitVectors(t,e){var n=t.X*e.X+t.Y*e.Y;if(n<-1||n>+1)n=Round(n,5);return Math.acos(n)}function Round(t,e){e=Math.pow(10,e);return Math.round(t*e)/e}function Deg2Rad(t){return t*Math.PI/180}function Rad2Deg(t){return t*180/Math.PI}