%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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;