summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/base/trembling.asy
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/asymptote/base/trembling.asy')
-rw-r--r--Build/source/utils/asymptote/base/trembling.asy492
1 files changed, 170 insertions, 322 deletions
diff --git a/Build/source/utils/asymptote/base/trembling.asy b/Build/source/utils/asymptote/base/trembling.asy
index 61e78a4fca3..6f6f5973332 100644
--- a/Build/source/utils/asymptote/base/trembling.asy
+++ b/Build/source/utils/asymptote/base/trembling.asy
@@ -1,246 +1,209 @@
-// Copyright (c) 2008, Philippe Ivaldi.
-// http://www.piprime.fr/
+// 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
+// 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.
+// 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
+// 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
+// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-// COMMENTARY:
+// COMMENTARY:
-// THANKS:
+// THANKS:
-// BUGS:
+// BUGS:
// magnetic points are experimental...
-// CODE:
+// CODE:
-import geometry;
-import stats;
-
-/*<asyxml><variable type="pair[]" signature="magneticPoints"><code></asyxml>*/
-pair[] magneticPoints;
-/*<asyxml></code><documentation>Array of magnetic points.
- When a point is magnetized, a trembled path will pass though P if the original path passes through P.
- When trembling is enabled with the routine 'startTrembling' all the drawn points is added to this array.
- For convenience, one can magnetize an arbitrary number of points with the routine 'magnetize'.<look href="#magnetize(...point[])"><look href="#startTrembling(real,real,real,real,bool">
- </documentation></variable></asyxml>*/
real magneticRadius=1; // unit is bp in postscript coordinates.
real trembleFuzz(){return min(1e-3,magneticRadius/10);}
-// real trembleFuzz(){return min(1e-1,1);}
-pair[] single(pair[] P)
+/* <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
{
- 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;
+ 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(allow) op.push(P[i]);
+ if(P.length > 0) op.push(P[P.length-1]);
+ return op;
}
- 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 nearest point of 'm' which is on the path g.
- '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;
- // do {
- // do {// Find a radius for intersection
- // r += step;
- // ig=T*scale(r)*unitcircle;
- // if(ig == g) {
- // T *= shift(shx,0);
- // ig=T*scale(r)*unitcircle;
- // }
- // t=intersect(ig,g);
- // } while(t.length <= 0 && r <= maxR && inside(g,ig) != 1);//
- // if(t.length <= 0) { // degenerated case
- // r=initr;
- // T *= shift(shx,0);
- // warning("atime","atime needs numerical adjustment.",position=true);
- // }
- // } while(t.length <= 0);
- 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];
+ /* <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;
}
- return ot;
-}
-
-/*<asyxml><function type="void" signature="magnetize(...pair[])"><code></asyxml>*/
-void magnetize(...pair[] P)
-{/*<asyxml></code><documentation>Magnetize the points P.
- When a point is magnetized, a trembled path will pass though P if the original path passes through P.</documentation></function></asyxml>*/
- if(magneticRadius <= 0) return;
- currentpicture.uptodate=false;
- currentpicture.nodes.insert(0,
- new void(frame f, transform t, transform T, pair lb, pair rt)
- {
- for (pair PT:P) {
- magneticPoints.push(t*PT);
- }
- });
-}
-/*<asyxml><function type="void" signature="magnetize(...triangle[])"><code></asyxml>*/
-void magnetize(...triangle[] t)
-{/*<asyxml></code><documentation>Magnetize the vertices of the triangles t.<look href="#magnetize(...pair[])"/></documentation></function></asyxml>*/
- for(int i=0; i < t.length; ++i)
- magnetize(...new point[] {t[i].A, t[i].B, t[i].C});
-}
-
-void trueMagnetize(pair p)
-{
- if(magneticRadius <= 0) return;
- magneticPoints.push(p);
-}
-
-/*<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);
- og=og..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);
+ /* <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;
}
- 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);
+ 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;
}
- return og;
-}
-
-
-/*<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>*/
-
-/*<asyxml><function type="path" signature="tremble(path,real,real,real,real)"><code></asyxml>*/
-path tremble(path g,
- real angle=trembleAngle,
- real frequency=trembleFrequency,
- real random=trembleRandom,
- real fuzz=trembleFuzz())
-{/*<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 'angle'.
- random is 0 means don't use randomized coefficient;
- More 'random' is hight more the coefficient is hight and the trembling seems randomized.</documentation></function></asyxml>*/
- if(length(g) == 0) return g;
- 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));
+ /* <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);
}
- else or=rsgn(unitrand())*1.5*angle;
- return or;
+ }
+ return og;
}
- real first=randf(), a=first;
- real gle;
- for(int i=1; i <= l; ++i)
+ /* <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);
- // gle=(i == l && (cyclic(tg))) ? first : a;
- // pair post=rotate(gle,point(tg,i-1))*postcontrol(tg,i-1);
- // pair pre=rotate(gle,P)*precontrol(tg,i);
- a=randf();
+ 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)))
@@ -248,121 +211,6 @@ path tremble(path g,
else
og=og..controls post and pre..P;
}
- return og;
-}
-
-typedef path pathModifier(path);
-pathModifier NoModifier=new path(path g){return g;};
-pathModifier tremble(real angle=trembleAngle,
- real frequency=trembleFrequency,
- real random=trembleRandom,
- real fuzz=trembleFuzz())
-{
- return new path(path g){return tremble(g,angle,frequency,random,fuzz);};
-}
-
-void orig_draw(frame f, path g, pen p=currentpen)=draw;
-void tremble_draw(frame f, path g, pen p=currentpen){}
-
-void tremble_marknodes(picture pic=currentpicture, frame f, path g) {}
-void tremble_markuniform(bool centered=false, int n, bool rotated=false) {}
-
-int tremble_circlenodesnumber(real r){return 5;}
-int orig_circlenodesnumber(real r)=circlenodesnumber;
-
-int tremble_circlenodesnumber1(real r, real angle1, real angle2){return 4;}
-int orig_circlenodesnumber1(real r, real angle1, real angle2)=circlenodesnumber;
-
-int tremble_ellipsenodesnumber(real a, real b){return 50;}
-int orig_ellipsenodesnumber(real a, real b)=ellipsenodesnumber;
-
-int tremble_ellipsenodesnumber1(real a, real b, real angle1, real angle2, bool dir){return 20;}
-int orig_ellipsenodesnumber1(real a, real b, real angle1, real angle2, bool dir)=ellipsenodesnumber;
-
-int tremble_parabolanodesnumber(parabola p, real angle1, real angle2){return 20;}
-int orig_parabolanodesnumber(parabola p, real angle1, real angle2)=parabolanodesnumber;
-
-int tremble_hyperbolanodesnumber(hyperbola h, real angle1, real angle2){return 20;}
-int orig_hyperbolanodesnumber(hyperbola h, real angle1, real angle2)=hyperbolanodesnumber;
-
-restricted bool tremblingMode=false;
-/*<asyxml><function type="void" signature="startTrembling(real,real,real,real,bool"><code></asyxml>*/
-void startTrembling(real angle=trembleAngle,
- real frequency=trembleFrequency,
- real random=trembleRandom,
- real fuzz=trembleFuzz(),
- bool magnetizePoints=true)
-{/*<asyxml></code><documentation>Calling this routine all drawn paths will be trembled with the givens parameters.<look href="#tremble(path,real,real,real,real)"/>
- If 'magnetizePoints' is true, most dotted points are automatically magnetized.<look href="magnetize(...pair[])"/></documentation></function></asyxml>*/
- if(!tremblingMode) {
- tremblingMode=true;
- tremble_draw=new void(frame f, path g, pen p=currentpen)
- {
- if(length(g) == 0 && magnetizePoints) {
- trueMagnetize(point(g,0));
- }
- g=addnodes(g,fuzz*abs(max(g)-min(g)) ...magneticPoints);
- orig_draw(f,tremble(g,angle,frequency,random,fuzz),p);
- };
-
- plain.draw=tremble_draw;
-
- if(magnetizePoints) {
- marknodes=new void(picture pic=currentpicture, frame f, path g)
- {
- for(int i=0; i <= length(g); ++i) {
- add(pic,f,point(g,i));
- magnetize(point(g,i));
- }
- };
- dot=dot();
-
- markuniform=new markroutine(bool centered=false, int n, bool rotated=false)
- {
- return new void(picture pic=currentpicture, frame f, path g) {
- if(n <= 0) return;
- void add(real x) {
- real t=reltime(g,x);
- add(pic,rotated ? rotate(degrees(dir(g,t)))*f : f,point(g,t));
- magnetize(point(g,t));
- }
- if(centered) {
- real width=1/n;
- for(int i=0; i < n; ++i) add((i+0.5)*width);
- } else {
- if(n == 1) add(0.5);
- else {
- real width=1/(n-1);
- for(int i=0; i < n; ++i)
- add(i*width);
- }
- }
- };
- };
- }
-
- circlenodesnumber=tremble_circlenodesnumber;
- circlenodesnumber=tremble_circlenodesnumber1;
-
- ellipsenodesnumber=tremble_ellipsenodesnumber;
- ellipsenodesnumber=tremble_ellipsenodesnumber1;
-
- parabolanodesnumber=tremble_parabolanodesnumber;
- hyperbolanodesnumber=tremble_hyperbolanodesnumber;
+ return og;
}
}
-
-// void stopTrembling()
-// {
-// if(tremblingMode) {
-// tremblingMode=false;
-// plain.draw=orig_draw;
-// // draw=orig_draw1;
-// circlenodesnumber=orig_circlenodesnumber;
-// circlenodesnumber=orig_circlenodesnumber1;
-// ellipsenodesnumber=orig_ellipsenodesnumber;
-// ellipsenodesnumber=orig_ellipsenodesnumber1;
-// parabolanodesnumber=orig_parabolanodesnumber;
-// hyperbolanodesnumber=orig_hyperbolanodesnumber;
-// }
-// }