summaryrefslogtreecommitdiff
path: root/graphics/asymptote/base/plain_filldraw.asy
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /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.asy248
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);
+}