summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/asymptote/trembling.asy
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/asymptote/trembling.asy')
-rw-r--r--Master/texmf-dist/asymptote/trembling.asy216
1 files changed, 216 insertions, 0 deletions
diff --git a/Master/texmf-dist/asymptote/trembling.asy b/Master/texmf-dist/asymptote/trembling.asy
new file mode 100644
index 00000000000..6f6f5973332
--- /dev/null
+++ b/Master/texmf-dist/asymptote/trembling.asy
@@ -0,0 +1,216 @@
+// Copyright(c) 2008, Philippe Ivaldi.
+// Simplified by John Bowman 02Feb2011
+// http: //www.piprime.fr/
+// trembling.asy: handwriting package for the software Asymptote.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+//(at your option) any later version.
+
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// COMMENTARY:
+
+// THANKS:
+
+// BUGS:
+// magnetic points are experimental...
+
+// CODE:
+
+real magneticRadius=1; // unit is bp in postscript coordinates.
+real trembleFuzz(){return min(1e-3,magneticRadius/10);}
+
+/* <asyxml> <variable type="real" signature="trembleAngle"> <code> </asyxml> */
+real trembleAngle=4, trembleFrequency=0.5, trembleRandom=2;
+/* <asyxml> </code> <documentation> Variables used by the routine 'tremble'.
+ </documentation> </variable> </asyxml> */
+
+struct tremble
+{
+ static real test=5;
+
+ real angle,frequency,random,fuzz;
+
+ pair[] single(pair[] P)
+ {
+ pair[] op;
+ bool allow;
+ for(int i=0; i < P.length-1; ++i) {
+ allow=true;
+ for(int j=i+1; j < P.length; ++j) {
+ if(abs(P[i]-P[j]) < magneticRadius) {
+ allow=false;
+ break;
+ }
+ }
+ if(allow) op.push(P[i]);
+ }
+ if(P.length > 0) op.push(P[P.length-1]);
+ return op;
+ }
+
+ /* <asyxml> <function type="pair" signature="attract(pair,path,real)"> <code>
+ </asyxml> */
+ real atime(pair m, path g, real fuzz=trembleFuzz())
+ {/* <asyxml> </code> <documentation> Return the time of the point on path g
+ nearest to 'm'.
+ 'fuzz' is the argument 'fuzz' of 'intersect'. </documentation> </function>
+ </asyxml> */
+ if(length(g) == 0) return 0.0;
+ real[] t=intersect(m,g,fuzz);
+ if(t.length > 0) return t[1];
+ real ot;
+ static real eps=sqrt(realEpsilon);
+ real abmax=abs(max(g)-m), abmin=abs(min(g)-m);
+ real initr=abs(m-midpoint(g));
+ real maxR=2*max(abmax,abmin), step=eps, r=initr;
+ real shx=1e-4;
+ transform T=shift(m);
+ path ig;
+ if(t.length > 0) ot=t[1];
+ real rm=0, rM=r;
+ while(rM-rm > eps) {
+ r=(rm+rM)/2;
+ t=intersect(T*scale(r)*unitcircle,g,fuzz);
+ if(t.length <= 0) {
+ rm=r;
+ } else {
+ rM=r;
+ ot=t[1];
+ }
+ }
+ return ot;
+ }
+
+ /* <asyxml> <function type="path" signature="addnode(path,real)"> <code>
+ </asyxml> */
+ path addnode(path g, real t)
+ {/* <asyxml> </code> <documentation> Add a node to 'g' at point(g,t).
+ </documentation> </function> </asyxml> */
+ real l=length(g);
+ real rt=t % 1;
+ if(l == 0 || (t > l && !cyclic(g)) || rt == 0) return g;
+ if(cyclic(g)) t=t % l;
+ int t0=floor(t);
+ int t1=t0+1;
+ pair z0=point(g,t0), z1=point(g,t1),
+ c0=postcontrol(g,t0), c1=precontrol(g,t1),
+ m0=(1-rt)*z0+rt*c0, m1=(1-rt)*c0+rt*c1,
+ m2=(1-rt)*c1+rt*z1, m3=(1-rt)*m0+rt*m1,
+ m4=(1-rt)*m1+rt*m2;
+ guide og=subpath(g,0,t0)..controls m0 and m3..point(g,t);
+ if(cyclic(g)) {
+ if(t1 < l)
+ og=og..controls m4 and m2..subpath(g,t1,l)&cycle;
+ else og=og..controls m4 and m2..cycle;
+ } else og=og..controls m4 and m2..subpath(g,t1,l);
+ return og;
+ }
+
+ path addnodes(path g, real fuzz=trembleFuzz()...pair[] P)
+ {
+ pair[] P=single(P);
+ if(length(g) == 0 || P.length == 0 || magneticRadius <= 0) return g;
+ path og=g;
+ for(pair tp: P) {
+ real t=atime(tp,og,fuzz);
+ real d=abs(tp-point(og,t));
+ if(d < magneticRadius) og=addnode(og,t);
+ }
+ return og;
+ }
+
+ /* <asyxml> <function type="path" signature="addnodes(path,int)"> <code>
+ </asyxml> */
+ path addnodes(path g, int n)
+ {/* <asyxml> </code> <documentation> Add 'n' nodes between each node of 'g'.
+ </documentation> </function> </asyxml> */
+ real l=length(g);
+ if(n == 0 || l == 0) return g;
+ path og=g;
+ int np=0;
+ for(int i=0; i < l; ++i) {
+ real step=1/(n+1);
+ for(int j=0; j < n; ++j) {
+ og=addnode(og,i*(n+1)+j+step);
+ step=1/(n-j);
+ }
+ }
+ return og;
+ }
+
+ /* <asyxml> <function type="path"
+ signature="tremble(path,real,real,real,real,pair[] )"> <code> </asyxml> */
+ void operator init(real angle=trembleAngle, real frequency=trembleFrequency,
+ real random=trembleRandom, real fuzz=trembleFuzz()) {
+ this.angle=angle;
+ this.frequency=frequency;
+ this.random=random;
+ this.fuzz=fuzz;
+ }
+
+ path deform(path g...pair[] magneticPoints) {
+ /* <asyxml> </code> <documentation> Return g as it was handwriting.
+ The postcontrols and precontrols of the nodes of g will be rotated
+ by an angle proportional to 'angle'(in degrees).
+ If frequency < 1, floor(1/frequency) nodes will be added to g to
+ increase the control points.
+ If frequency>= 1, one point for floor(frequency) will be used to deform
+ the path.
+ 'random' controls the randomized coefficient which will be multiplied
+ by 'angle'.
+ random is 0 means don't use randomized coefficient;
+ The higher 'random' is, the more the trembling is randomized.
+ </documentation> </function> </asyxml> */
+ if(length(g) == 0) return g;
+ g=addnodes(g,fuzz*abs(max(g)-min(g))...magneticPoints);
+ path tg=g;
+ frequency=abs(frequency);
+ int f=abs(floor(1/frequency)-1);
+ tg=addnodes(tg,f);
+ int frequency=floor(frequency);
+ int tf=(frequency == 0) ? 1 : frequency;
+ int l=length(tg);
+ guide og=point(tg,0);
+ random=abs(random);
+ int rsgn(real x){
+ int d2=floor(100*x)-10*floor(10*x);
+ if(d2 == 0) return 1;
+ return 2 % d2 == 0 ? 1 : -1;
+ }
+ real randf()
+ {
+ real or;
+ if(random != 0) {
+ if(1 % tf != 0) or=0;
+ else {
+ real ur=unitrand();
+ or=rsgn(ur)*angle*(1+ur^(1/random));
+ }
+ } else or=rsgn(unitrand())*1.5*angle;
+ return or;
+ }
+
+ real first=randf();
+ for(int i=1; i <= l; ++i) {
+ pair P=point(tg,i);
+ real a=randf();
+ pair post=rotate(a,point(tg,i-1))*postcontrol(tg,i-1);
+ pair pre=rotate((a+randf())/2,P)*precontrol(tg,i);
+ if(i == l && (cyclic(tg)))
+ og=og..controls post and pre..cycle;
+ else
+ og=og..controls post and pre..P;
+ }
+ return og;
+ }
+}