MetaPost outputs PostScript, and PostScript draws solid areas (I think). So, transparency may not be achieved without drawing anew background picture. That's heavy, memory consuming and certainly not elegant.
Suppose that a currentpicture is given.
You want to put on this picture some filled cycle path
c with color yourcolor and
transparency factor transparency.
What would be nice is extracting exactly what in
currentpicture is enclosed within
the path c; then draw this with a
color which would be intermediate between
yourcolor and the original color.
If it was possible to remove the previous picture
enclosed within the path c as it
may happen for pixelized output, it would be very
nice nice since it would mean that the output's size
wouldn't grow to much.
In one of John Hobby's manuals is described the way to extract informations from the currentpicture, especially the control sequence
for <symbolic token> within <picture>.
I have currentpicture, a cycle path
c, a transparency factor
transparency and a color
yourcolor. What I may do is:
c with the background color
and take care that it will be at the back most level. The reason for
that will be clear later.currentpicture,
draw this subpicture into a temporary picture with
some intermediate color.c.currentpicture.
The reason for having added some blank picture at the begining
is that when the path covers the background, it should be visible.
So that this part must exist within the currentpicture.
%
% settings
%
color yourcolor; yourcolor=red;
transparency:=0.75;
%
% usage: transparentfill <cyclic path>;
%
vardef transparentfill expr c=
save p_; picture p_;
p_=currentpicture;
currentpicture:=nullpicture;
fill c withcolor background;
addto currentpicture also p_;
p_:=nullpicture;
for p within currentpicture:
addto p_ also p withcolor
transparency[yourcolor,(redpart p,greenpart p,bluepart p)];
endfor
clip p_ to c;
draw p_;
enddef;
A sample. Just the one on the right.
Why is it so bad? Try to fill two transparent areas that overlay. Their intersection will be opaque. Let's see why.
Suppose given a usual picture (no clipped area).
First fill cyclic path c1
with the transparentfill control
sequence. This will add on top of the
currentpicture a plain subpicture
p1 whose nature is quite different
from usual pictures (solid filled areas, strokes,
...): it is a clipped picture.
Now fill cyclic path
c2 with the transparentfill
control sequence. Processing transparentfill,
first will come the original currentpicture,
say originalpicture,
which will be treated right as before. At last will
come p1 which will be seen a single
object whose contour is c1 and color
(0,0,0).
Now you can guess what will
happen: to the temporary picture p_
is added the contour c1 filled with
an intermediate color between black and
yourcolor. Then p_ is
clipped to c2 to obtain, say, p2
and added to currentpicture which is now equal
to originalpicture + p1 + p2 (order matters),
and which is not what you wanted it to be.
Fortunately, there exists a boolean valued operator
named clipped, so that it is possible
in the previous loop to detect whether p
is a clipped picture or not. If it is, one has to
examin it deeper (and here comes recursivity).
The following code makes that
stuff. It is quite heavy and non-elegant. In fact,
since there is a very little documentation about
MetaPost processing, I just made some
random-binary-script-writting. The fact is that it
seems to work (it will be improved).
color yourcolor; yourcolor:=blue;
picture AlphaPict; AlphaPict=nullpicture;
Alpha:=0.25;
def AlphaFill expr c=
AlphaPict:=nullpicture;
AlphaPicture(currentpicture,c);
addto currentpicture also AlphaPict;
enddef;
vardef AlphaPicture(expr p,c)=
save p_; picture p_;
p_=nullpicture;
addto p_ contour c withcolor Alpha[background,yourcolor];
for p__ within p:
if (not clipped p__) and (not bounded p__):
addto p_ also p__ withcolor
Alpha[(redpart p__,greenpart p__,bluepart p__),yourcolor];
else:
begingroup save AlphaPict;
picture AlphaPict; AlphaPict=nullpicture;
AlphaPicture(p__,pathpart p__);
addto p_ also AlphaPict;
endgroup;
fi
endfor
clip p_ to c;
addto AlphaPict also p_;
enddef;
A sample.
Just the one on the right.
That's my usual Dangerous sign. I've filled
(AlphaFill <path>)
four partially overlapping squares.
A simple thing to do in order to improve previous code is to draw subpicture if and only if its bounding box intersects the bounding box of the path. Here is more or less the code implemented in my statsmac package.
picture alphapict_; alphapict_=nullpicture;
color fillcolor; fillcolor=red;
fgalpha := 0.5; % usual alpha parameter
bgalpha:= 1; % alpha parameter with respect to the background
vardef alphafill expr c =
alphapict_ := nullpicture;
alphafill_(currentpicture, c);
addto currentpicture also alphapict_;
enddef;
def alphafill_(expr p, c) =
begingroup
save p_, xmax_, xmin_, ymax_, ymin_; picture p_;
p_ = nullpicture;
(xmin_, ymin_) = llcorner c; (xmax_, ymax_) = urcorner c;
addto p_ contour c withcolor bgalpha[background, fillcolor];
for p__ within p:
numeric xmin__, xmax__, ymin__, ymax__;
(xmin__, ymin__) = llcorner p__; (xmax__, ymax__) = urcorner p__;
if (xmax__<= xmin_) or (xmin__ >= xmax_):
else:
if (ymax__<= ymin_) or (ymin__ >= ymax_):
else:
if (not clipped p__) and (not bounded p__):
addto p_ also p__ withcolor
fgalpha[(redpart p__, greenpart p__, bluepart p__),
fillcolor];
else:
begingroup save alphapict_;
picture alphapict_; alphapict_ = nullpicture;
alphafill_(p__, pathpart p__);
addto p_ also alphapict_;
endgroup;
fi
fi
fi
endfor
clip p_ to c;
addto alphapict_ also p_;
endgroup;
enddef;
A sample. Just the one on the right. That's some local building. I replace the sphere by a transparent cube (lighter). One should notice that the text is made of clipped and transformed text pictures (that's postscript fonts, I did not try bitmap fonts yet), so that the macro seems to work quite well.
If you have some better ideas, let me know!