diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/asymptote/base/plain_filldraw.asy |
Initial commit
Diffstat (limited to 'graphics/asymptote/base/plain_filldraw.asy')
-rw-r--r-- | graphics/asymptote/base/plain_filldraw.asy | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/graphics/asymptote/base/plain_filldraw.asy b/graphics/asymptote/base/plain_filldraw.asy new file mode 100644 index 0000000000..026f2cee6c --- /dev/null +++ b/graphics/asymptote/base/plain_filldraw.asy @@ -0,0 +1,248 @@ +// Draw path g on frame f with user-constructed pen p. +void makedraw(frame f, path g, pen p, int depth=mantissaBits) +{ + if(depth == 0) return; + --depth; + + path n=nib(p); + for(int i=0; i < size(g); ++i) + fill(f,shift(point(g,i))*n,p); + + static real epsilon=1000*realEpsilon; + int L=length(g); + real stop=L-epsilon; + int N=length(n); + pair first=point(n,0); + pair n0=first; + + for(int i=0; i < N; ++i) { + pair n1=point(n,i+1); + pair dir=unit(n1-n0); + real t=dirtime(g,-dir)-epsilon; + if(straight(g,(int) t)) t=ceil(t); + if(t > epsilon && t < stop) { + makedraw(f,subpath(g,0,t),p,depth); + makedraw(f,subpath(g,t,L),p,depth); + return; + } + real t=dirtime(g,dir); + if(straight(g,(int) t)) t=ceil(t); + if(t > epsilon && t < stop) { + makedraw(f,subpath(g,0,t),p,depth); + makedraw(f,subpath(g,t,L),p,depth); + return; + } + n0=n1; + } + + n0=first; + for(int i=0; i < N; ++i) { + pair n1=point(n,i+1); + fill(f,shift(n0)*g--shift(n1)*reverse(g)--cycle,p); + n0=n1; + } +} + +void draw(frame f, path g, pen p=currentpen) +{ + if(size(nib(p)) == 0) _draw(f,g,p); + else { + begingroup(f); + makedraw(f,g,p); + endgroup(f); + } +} + +void draw(frame f, explicit path[] g, pen p=currentpen) +{ + for(int i=0; i < g.length; ++i) draw(f,g[i],p); +} + +void draw(frame f, guide[] g, pen p=currentpen) +{ + for(int i=0; i < g.length; ++i) draw(f,g[i],p); +} + +void filldraw(frame f, path[] g, pen fillpen=currentpen, + pen drawpen=currentpen) +{ + begingroup(f); + fill(f,g,fillpen); + draw(f,g,drawpen); + endgroup(f); +} + +path[] complement(frame f, path[] g) +{ + static pair margin=(0.5,0.5); + return box(minbound(min(f),min(g))-margin,maxbound(max(f),max(g))+margin)^^g; +} + +void unfill(frame f, path[] g, bool copy=true) +{ + clip(f,complement(f,g),evenodd,copy); +} + +void filloutside(frame f, path[] g, pen p=currentpen, bool copy=true) +{ + fill(f,complement(f,g),p+evenodd,copy); +} + +struct filltype +{ + typedef void fill2(frame f, path[] g, pen fillpen); + fill2 fill2; + pen fillpen; + pen drawpen; + + int type; + static int Fill=1; + static int FillDraw=2; + static int Draw=3; + static int NoFill=4; + static int UnFill=5; + + void operator init(int type=0, pen fillpen=nullpen, pen drawpen=nullpen, + fill2 fill2) { + this.type=type; + this.fillpen=fillpen; + this.drawpen=drawpen; + this.fill2=fill2; + } + void fill(frame f, path[] g, pen p) {fill2(f,g,p);} +} + +path[] margin(path[] g, real xmargin, real ymargin) +{ + if(xmargin != 0 || ymargin != 0) { + pair M=max(g); + pair m=min(g); + real width=M.x-m.x; + real height=M.y-m.y; + real xfactor=width > 0 ? (width+2xmargin)/width : 1; + real yfactor=height > 0 ? (height+2ymargin)/height : 1; + g=scale(xfactor,yfactor)*g; + g=shift(0.5*(M+m)-0.5*(max(g)+min(g)))*g; + } + return g; +} + +filltype Fill(real xmargin=0, real ymargin=xmargin, pen p=nullpen) +{ + return filltype(filltype.Fill,p,new void(frame f, path[] g, pen fillpen) { + if(p != nullpen) fillpen=p; + if(fillpen == nullpen) fillpen=currentpen; + fill(f,margin(g,xmargin,ymargin),fillpen); + }); +} + +filltype FillDraw(real xmargin=0, real ymargin=xmargin, + pen fillpen=nullpen, pen drawpen=nullpen) +{ + return filltype(filltype.FillDraw,fillpen,drawpen, + new void(frame f, path[] g, pen Drawpen) { + if(drawpen != nullpen) Drawpen=drawpen; + pen Fillpen=fillpen == nullpen ? Drawpen : fillpen; + if(Fillpen == nullpen) Fillpen=currentpen; + if(Drawpen == nullpen) Drawpen=Fillpen; + if(cyclic(g[0])) + filldraw(f,margin(g,xmargin,ymargin),Fillpen,Drawpen); + else + draw(f,margin(g,xmargin,ymargin),Drawpen); + }); +} + +filltype Draw(real xmargin=0, real ymargin=xmargin, pen p=nullpen) +{ + return filltype(filltype.Draw,drawpen=p, + new void(frame f, path[] g, pen drawpen) { + pen drawpen=p == nullpen ? drawpen : p; + if(drawpen == nullpen) drawpen=currentpen; + draw(f,margin(g,xmargin,ymargin),drawpen); + }); +} + +filltype NoFill=filltype(filltype.NoFill,new void(frame f, path[] g, pen p) { + draw(f,g,p); + }); + + +filltype UnFill(real xmargin=0, real ymargin=xmargin) +{ + return filltype(filltype.UnFill,new void(frame f, path[] g, pen) { + unfill(f,margin(g,xmargin,ymargin)); + }); +} + +filltype FillDraw=FillDraw(), Fill=Fill(), Draw=Draw(), UnFill=UnFill(); + +// Fill varying radially from penc at the center of the bounding box to +// penr at the edge. +filltype RadialShade(pen penc, pen penr) +{ + return filltype(new void(frame f, path[] g, pen) { + pair c=(min(g)+max(g))/2; + radialshade(f,g,penc,c,0,penr,c,abs(max(g)-min(g))/2); + }); +} + +filltype RadialShadeDraw(real xmargin=0, real ymargin=xmargin, + pen penc, pen penr, pen drawpen=nullpen) +{ + return filltype(new void(frame f, path[] g, pen Drawpen) { + if(drawpen != nullpen) Drawpen=drawpen; + if(Drawpen == nullpen) Drawpen=penc; + pair c=(min(g)+max(g))/2; + if(cyclic(g[0])) + radialshade(f,margin(g,xmargin,ymargin),penc,c,0,penr,c, + abs(max(g)-min(g))/2); + draw(f,margin(g,xmargin,ymargin),Drawpen); + }); +} + +// Fill the region in frame dest underneath frame src and return the +// boundary of src. +path fill(frame dest, frame src, filltype filltype=NoFill, + real xmargin=0, real ymargin=xmargin) +{ + pair z=(xmargin,ymargin); + path g=box(min(src)-z,max(src)+z); + filltype.fill(dest,g,nullpen); + return g; +} + +// Add frame dest to frame src with optional grouping and background fill. +void add(frame dest, frame src, bool group, filltype filltype=NoFill, + bool above=true) +{ + if(above) { + if(filltype != NoFill) fill(dest,src,filltype); + if(group) begingroup(dest); + add(dest,src); + if(group) endgroup(dest); + } else { + if(group) { + frame f; + endgroup(f); + prepend(dest,f); + } + prepend(dest,src); + if(group) { + frame f; + begingroup(f); + prepend(dest,f); + } + if(filltype != NoFill) { + frame f; + fill(f,src,filltype); + prepend(dest,f); + } + } +} + +void add(frame dest, frame src, filltype filltype, + bool above=filltype.type != filltype.UnFill) +{ + if(filltype != NoFill) fill(dest,src,filltype); + (above ? add : prepend)(dest,src); +} |