%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This file is part of the MPATTERN package
%
% mpattern.mp: MetaPost macros for pattern defining and filling
%
% Author: Piotr Bolek
% version 0.5: (Jun 25, 2001)
%
% $Id: mpattern.mp,v 1.3 2001/06/25 07:28:14 piotrek Exp $
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

boolean P_dict_;
boolean P_used_already_;
% Record all numbers (charcode) of pictures
extra_beginfig := extra_beginfig
  & "numeric Pwritten_[]; Pcharcode_[charcode]=1; P_used_already_:=false; P_dict_:=false;";

% Working variables to store fragments of Pattern definition
string PBBox_, PHead_, PTail_, PPaintProc_, Pname_, Pdefs_;
string Pmatrix_;

PHead_="<< /PaintType 1 /PatternType 1 /TilingType 1 ";
% 11.08.98 PPaintProc_="/PaintProc { begin ";
PPaintProc_="/PaintProc {  pop ";
% 11.08.98 PTail_=" end } >>"; % matrix makepattern";
PTail_="  } >>"; % matrix makepattern";
Pdefs_="";
   
% New line string
string Pnl_; Pnl_=char 13;

% Number of defined patterns
numeric Pnum_; Pnum_=0;

% Split string defining pattern on new line chars
% and use each piece as argument to special
vardef Psplit_and_write_(expr s)=
   save Pfirst_, Plast_;
   Pfirst_:=0; Plast_:=0;
   for i=0 upto length(s):
      if ( substring (i,i+1) of s = Pnl_ ):
	 Plast_:=i;
	 special substring (Pfirst_,Plast_) of s;
	 Pfirst_:=i+1;
      fi;
   endfor;
enddef;

% Find maximum charcode not used for picture yet
vardef Pmax_charcode_=
   save Pn_;
   for i=999 downto 1:
      Pn_:=i;
      exitif unknown Pcharcode_[i];
   endfor;
   Pn_
enddef;

def PmakeBB_=
   PBBox_ := "/BBox [" & decimal Plft_ & " " & decimal Plow_ & " "
   & decimal Prt_ & " " & decimal Pup_ & "]" & Pnl_;
enddef;

def Psteps_=
   PBBox_ := PBBox_ & "/XStep " & decimal
   if unknown PXStep_: (Prt_-Plft_) else: PXStep_ fi & Pnl_
   & "/YStep " & decimal
   if unknown PYStep_:  (Pup_-Plow_) else: PYStep_ fi;
enddef;
   
vardef Pfindbounds_=
%   save Plow_, Plft_, Pup_, Prt_;
%   numeric Plow_, Plft_, Pup_, Prt_;

   Plow_ = ypart (llcorner currentpicture);
   Plft_ = xpart (llcorner currentpicture);
   Pup_ = ypart (urcorner currentpicture);
   Prt_ = xpart (urcorner currentpicture);
   
   PmakeBB_;
enddef;

% Read file in which the body of patterns PaintProc is stored
vardef PReadFile_=
   save Pfile_, Pline_, Pall_;
   string Pfile_, Pline_, Pall_;
   Pline_=Pall_="";
   Pfile_:=jobname & "." & decimal charcode;
   forever:
      Pline_ := readfrom Pfile_;
      exitif Pline_ = EOF;
      if (substring(length Pline_-3,length Pline_) of Pline_ = "def")
	  and (substring (0,6) of Pline_ <> "/fshow"):
	 Pdefs_ := Pdefs_ & Pline_ & Pnl_;
      else:
	   if (substring (0,2) of Pline_ = "%%")
	      or (substring (0,8) of Pline_ = "showpage")
	      or (substring (0,4) of Pline_ = "%!PS")
	      or (substring (0,6) of Pline_ = "/fshow"):
	   else:
		Pall_:=Pall_ & Pline_ & Pnl_;
	   fi;
      fi;
   endfor;
   Pall_
enddef;

% Join all parts of pattern definition 
vardef PmakePattern_(expr name)=
   save Pread_;
   string Pread_;

   Pread_ = PReadFile_;
   
   % Write string used later to identify pattern
%   batchmode;
%   message "Defining pattern " & name & "->" & decimal (Pnum_*epsilon);
%   errorstopmode;
   "% Pattern:" &
      if (not known PColor_):
          decimal (Pnum_*epsilon)
      else:
          decimal (PColor_)
      fi
      & ":" & name & Pnl_
      & PHead_ & Pnl_
      & PBBox_ & Pnl_
      & Pdefs_
      & PPaintProc_ & Pnl_
      & Pread_ 
      & PTail_ & Pnl_
      & Pmatrix_ & " makepattern" & Pnl_
      & "/" & name & " exch def" & Pnl_
      & "MPP " &
      if (not known PColor_):
	decimal (Pnum_*epsilon)
      else:
	decimal (PColor_)
      fi
      & " " & name & " put"  & Pnl_
enddef;

% find PatternColor -- color which will be replaced by pattern
vardef Pfindcolor_(expr s)=
   save Pfirst_, Plast_;
   numeric Pfirst_, Plast_;
   Pfirst_=Plast_=0;
   for i=0 upto 255:
      if substring(i,i+1) of s=":":
	 if Pfirst_=0:
	    Pfirst_:=i+1;
	 else:
	      Plast_:=i;
	 fi;
      fi;
      exitif Plast_<>0;
   endfor;
   scantokens (substring (Pfirst_,Plast_) of s)
enddef;

%%%%%%%%%%%%%% User interface macros

% Define BoundingBox of pattern
vardef patternbbox(expr a)(text b)=
%   save Plft_, Plow_, Prt_, Pup_, Pi_, Pz_;
%   numeric Plft_, Plow_, Prt_, Pup_, Pi_, Pz_[];
   save Pi_, Pz_;
   numeric Pi_, Pz_[];
   if pair a:
      Plft_:=min(xpart(a),xpart(b)); Plow_:=min(ypart(a),ypart(b));
      Prt_:=max(xpart(a),xpart(b));  Pup_:=max(ypart(a),ypart(b));
   else:
      Pi_=1;
      for t=b:
	 Pz_[Pi_]=t;
	 Pi_:=Pi_+1;
      endfor;
      Plft_:=min(a,Pz_2);   Plow_:=min(Pz_1,Pz_3);
      Prt_:=max(a,Pz_2); Pup_:=max(Pz_1,Pz_3);
   fi;

   PmakeBB_;
enddef;

def beginpattern(suffix name)=
   numeric PXStep_, PYStep_;
   numeric Plow_, Plft_, Pup_, Prt_;
   numeric PColor_;
   Pmatrix_:=" matrix ";

   % Declare variable in which the pattern definition will be stored
   string name;
   Pname_:=str name;

   Pnum_:=Pnum_+1;
   
   % Use the largest available picture number (charcode)
   % for storing the body od patten PaintProc
   beginfig(Pmax_charcode_);
enddef;

def endpattern=
   if unknown PBBox_:
      Pfindbounds_;
   fi;
   endfig;
   Psteps_;

   begingroup;
   save Punknown_, Ppattern_;
   string Punknown_, Ppattern_;

   Ppattern_=PmakePattern_(Pname_);
   % free used charcode
   Pcharcode_[charcode]:=whatever;
   PBBox_:=Punknown_;
   Pdefs_:="";
   % Assign pattern to string variable
   scantokens(Pname_ & "=Ppattern_;");
   endgroup;
enddef;

primarydef p withpattern s=
   hide(
     if not P_dict_:       
       special "/MPP 100 dict def";
       special "/MPPshow {exch findfont exch scalefont setfont show}bind def";
       special "/fill { MPP currentgray known " & char 10 
       & "      { MPP currentgray get setpattern fill } { fill } " & char 10
       & "        ifelse } bind def";
       special "/fshow { MPP currentgray known " & char 10 
       & "      { MPP currentgray get setpattern MPPshow } { MPPshow } " & char 10
       & "        ifelse } bind def";
       P_dict_:=true;
     fi;
      Pc_:=Pfindcolor_(s);
	% write definition of pattern used in picture
	% but not yet written to output file;
	if unknown Pwritten_[Pc_]:
	   Psplit_and_write_(s);
	   Pwritten_[Pc_]:=1;
	fi;
	if not P_used_already_:
           batchmode;
           message "Pattern:" & decimal charcode;
           errorstopmode;
	   P_used_already_:=true;
	fi;
      %show p;
	)
   p withcolor Pc_*white
enddef;
   
def patterntransform expr t=
   Pmatrix_ := "[ " & decimal xxpart t
              & " " & decimal yxpart t
              & " " & decimal xypart t
              & " " & decimal yypart t
              & " " & decimal xpart t
              & " " & decimal ypart t & " ]";
%   show Pmatrix_;
enddef;

def patternxstep expr t=
   show t;
   PXStep_ = t;
enddef;

def patternystep expr t=
   show t;
   PYStep_ = t;
enddef;

def patternstep text t=
   show t;
   if pair t:
      PXStep_ = xpart t;
      PYStep_ = ypart t;
   else:
      (PXStep_,PYStep_)=t;
   fi;
enddef;

def patterncolor expr t=
   show t;
   PColor_ = t;
enddef;
