Page d'accueil du laboratoire > Équipe de Probabilités > Page principale > > MetaPost
Propaganda, Exemples, m3Dplain, Statsmac, Animations, Transparence,

associaedre ou polytope de Stasheff

Transparency and MetaPost

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.

Before reading further

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>.

1. First attempt

I have currentpicture, a cycle path c, a transparency factor transparency and a color yourcolor. What I may do is:

  1. Fill the cycle path 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.
  2. For every subpicture in currentpicture, draw this subpicture into a temporary picture with some intermediate color.
  3. Clip the temporary picture to the cycle path c.
  4. Draw the temporary picture into the 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;
alphapic1

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.

2. Second attempt

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.

alphapic2

3. Third attempt

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.

alphapic3

Improvements?

If you have some better ideas, let me know!


Copyright: HTML's texts or graphics are free of any copyright, they are copyleft. TeX programs are also copyleft but one can send a postcard. MetaPost programs have just a feel-free-to-send-me-a-postcard licence.
Valid HTML 4.01!
Anthony Phan,
Département de Mathématiques, SP2MI,
Boulevard Marie et Pierre Curie, Téléport 2,
BP 30179, F-86962 Futuroscope-Chasseneuil cedex