summaryrefslogtreecommitdiff
path: root/graphics/MF-PS
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/MF-PS
Initial commit
Diffstat (limited to 'graphics/MF-PS')
-rw-r--r--graphics/MF-PS/0mf-ps.doc52
l---------graphics/MF-PS/README1
-rw-r--r--graphics/MF-PS/epstomf/0epstomf.doc38
l---------graphics/MF-PS/epstomf/README1
-rw-r--r--graphics/MF-PS/epstomf/e2mform/0e2mform.doc25
-rw-r--r--graphics/MF-PS/epstomf/e2mform/mft-pl.bat15
-rw-r--r--graphics/MF-PS/epstomf/e2mform/mftform.tex61
-rw-r--r--graphics/MF-PS/epstomf/e2mform/mftmac.tex55
-rw-r--r--graphics/MF-PS/epstomf/e2mform/mimulcol.tex286
-rw-r--r--graphics/MF-PS/epstomf/e2mform/pl.mft111
-rw-r--r--graphics/MF-PS/epstomf/epstomf.awk375
-rw-r--r--graphics/MF-PS/mftoeps/0mftoeps.doc218
l---------graphics/MF-PS/mftoeps/README1
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/0m2esamp.doc35
l---------graphics/MF-PS/mftoeps/m2esamp/README1
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/clipcir.mf39
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/clipsqu.mf39
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/holeclip.mf20
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/holeclip.tex22
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/holefill.mf21
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/polygons.mf32
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/rectan.mf19
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/rectan_.bat4
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample1a.mf24
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample1b.mf28
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample2a.mf23
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample2b.mf23
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample2c.mf23
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample2d.mf23
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample2e.mf23
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample3.mf53
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample4.mf45
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/sample5.mf38
-rw-r--r--graphics/MF-PS/mftoeps/m2esamp/stereo.mf53
-rw-r--r--graphics/MF-PS/mftoeps/mftoeps.mf748
-rw-r--r--graphics/MF-PS/progs/0progs.doc25
l---------graphics/MF-PS/progs/README1
-rw-r--r--graphics/MF-PS/progs/e2m.bat11
-rw-r--r--graphics/MF-PS/progs/m2e-alt.bat30
-rw-r--r--graphics/MF-PS/progs/m2e.bat26
-rw-r--r--graphics/MF-PS/progs/spliteps.awk9
-rw-r--r--graphics/MF-PS/progs/spliteps.tex83
-rw-r--r--graphics/MF-PS/progs/tex.bat8
-rw-r--r--graphics/MF-PS/roex/0roex.doc36
l---------graphics/MF-PS/roex/README1
-rw-r--r--graphics/MF-PS/roex/roex.mf1756
-rw-r--r--graphics/MF-PS/roex/roexsamp/0roexsam.doc69
l---------graphics/MF-PS/roex/roexsamp/README1
-rw-r--r--graphics/MF-PS/roex/roexsamp/es-01.mf29
-rw-r--r--graphics/MF-PS/roex/roexsamp/es-02.mf32
-rw-r--r--graphics/MF-PS/roex/roexsamp/es-03.mf43
-rw-r--r--graphics/MF-PS/roex/roexsamp/ro-01.mf26
-rw-r--r--graphics/MF-PS/roex/roexsamp/ro-02.mf33
-rw-r--r--graphics/MF-PS/roex/roexsamp/ro-03.mf34
-rw-r--r--graphics/MF-PS/roex/roexsamp/ro-04.mf49
-rw-r--r--graphics/MF-PS/roex/roexsamp/ro-05.mf45
-rw-r--r--graphics/MF-PS/roex/roexsamp/ro-06.mf150
-rw-r--r--graphics/MF-PS/roex/roexsamp/ro-07.mf102
-rw-r--r--graphics/MF-PS/roex/roexsamp/roes-01.mf38
-rw-r--r--graphics/MF-PS/roex/roexsamp/roes-02.mf33
-rw-r--r--graphics/MF-PS/roex/roexsamp/roes-03.mf49
-rw-r--r--graphics/MF-PS/roex/roexsamp/roes-04.mf91
62 files changed, 5385 insertions, 0 deletions
diff --git a/graphics/MF-PS/0mf-ps.doc b/graphics/MF-PS/0mf-ps.doc
new file mode 100644
index 0000000000..3b9c587d9f
--- /dev/null
+++ b/graphics/MF-PS/0mf-ps.doc
@@ -0,0 +1,52 @@
+DIRECTORY OVERVIEW
+
+The directory contains the following subdirectories:
+ MFTOEPS
+ EPSTOMF
+ PROGS
+ ROEX
+
+Detailed description can be found either in DOC-files or in the source files
+in the subdirectories.
+
+-----------------------------------------------------------------------------
+
+BRIEF DESCRIPTION OF THE CONTENTS
+
+MFTOEPS: a METAFONT package for generating (encapsulated PostScript) files
+ readable by CorelDRAW!(R), Adobe Illustrator(TM) and Fontographer(R).
+ METAFONT writes PostScript code to a LOG-file, and from the LOG-file
+ the code can be extracted by either TeX or AWK. DOS batch files,
+ TeX source, and AWK source are placed in the subdirectory PROGS.
+
+EPSTOMF: a tiny AWK script for converting EPS files into MF lingo.
+ EPS files should conform the conventions of the MFTOEPS package.
+ Such files are generated, e.g., by a Ghostscript utility which
+ can be found in a directory: support/ps_conv/ on every CTAN
+ or ftp.GUST.org.pl/pub/TeX/support/ps_conv/.
+
+ROEX: a set of METAFONT macros for accomplishing operations known
+ as `removing overlaps' and `expanding stroke.' It can work
+ with ``normal'' METAFONT programs, but is meant mainly for
+ using with MFTOEPS; in this context it seems most natural.
+
+PROGS: a directory containing DOS batch files, AWK and TeX programs
+ used by the packages listed above.
+
+-----------------------------------------------------------------------------
+
+AUTHORS' COORDINATES
+
+Mail: BOP s.c., ul. Piastowska 70, 80-363 Gda\'nsk, Poland
+Email: B.Jackowski@GUST.ORG.PL
+
+-----------------------------------------------------------------------------
+HISTORY:
+ 29 X 1995: first less or more complete release
+ 6 XI 1995: package EPSTOMF touched
+ 25 III 1997: revised release of packages MFTOEPS and EPSTOMF
+ 29 I 1998: revised release of package EPSTOMF (modifications
+ suggested by Samy Alex Za\"\i{}mi)
+-----------------------------------------------------------------------------
+
+END OF THE 0MF-PS.DOC FILE
diff --git a/graphics/MF-PS/README b/graphics/MF-PS/README
new file mode 120000
index 0000000000..1152b6f5ee
--- /dev/null
+++ b/graphics/MF-PS/README
@@ -0,0 +1 @@
+0mf-ps.doc \ No newline at end of file
diff --git a/graphics/MF-PS/epstomf/0epstomf.doc b/graphics/MF-PS/epstomf/0epstomf.doc
new file mode 100644
index 0000000000..dd778337ba
--- /dev/null
+++ b/graphics/MF-PS/epstomf/0epstomf.doc
@@ -0,0 +1,38 @@
+This file belongs to the EPSTOMF package.
+
+-----------------------------------------------------------------------------
+
+BRIEF DESCRIPTION
+
+The AWK program, EPSTOMF.AWK, converts EPS files, conforming the convention
+of files produced using the MFTOEPS package, into METAFONT lingo (see the
+batch file E2M.BAT in the subdirectory ../PROGS). Primarily, it is meant as
+a supplementary link between PostScript and METAFONT, collaborating with
+the PostScript-to-EPS converter, PS_CONV, which can be found in
+the subdirectory ../../PS/PS_CONV.
+
+For the details of conversion see the EPSTOMF.AWK file.
+
+Additionally, there are some files for a neat formatting of the resulting
+METAFONT files in the subdirectory E2MFORM. This is our idiosyncrasy; if you
+prefer other formatting (e.g., verbatim)---feel free to delete all the stuff.
+
+-----------------------------------------------------------------------------
+
+All copyrights, copylefts, copyups, copydowns, or whatever you wish to call
+them, concerning the EPSTOMF.AWK are essentially of the public domain
+character. In particular, you are entitled to do with the file whatever you
+wish. If you alter a file, however, please remove the line containing the
+comment:
+
+ `This file belongs to the EPSTOMF package.'
+
+in order to avoid mess.
+
+The files in the directory E2MFORM are not the part of the EPSTOMF
+distribution, however, they belong to public domain (as far as we know),
+therefore we assumed that it is fair to include them here.
+
+-----------------------------------------------------------------------------
+
+END OF THE 0EPSTOMF.DOC FILE
diff --git a/graphics/MF-PS/epstomf/README b/graphics/MF-PS/epstomf/README
new file mode 120000
index 0000000000..40913726a7
--- /dev/null
+++ b/graphics/MF-PS/epstomf/README
@@ -0,0 +1 @@
+0epstomf.doc \ No newline at end of file
diff --git a/graphics/MF-PS/epstomf/e2mform/0e2mform.doc b/graphics/MF-PS/epstomf/e2mform/0e2mform.doc
new file mode 100644
index 0000000000..029c5fd28b
--- /dev/null
+++ b/graphics/MF-PS/epstomf/e2mform/0e2mform.doc
@@ -0,0 +1,25 @@
+This file belongs to the EPSTOMF package.
+
+The directory E2MFORM contains the files for a ``neat'' printing of METAFONT
+files generated by the EPSTOMF utility. The directory contains the following
+files:
+
+0E2MFORM.DOC -- this file
+MFT-PL.BAT -- sample DOS batch file calling the MFT utility
+MFTFORM.TEX -- special TeX format for the MFT utility
+MFTMAC.TEX -- general TeX format for the MFT utility
+MIMULCOL.TEX -- Frank Mittelbach's multicolumn format
+ (plain TeX adaptation of an archaic version)
+PL.MFT -- data for the MFT utility taken from the MeX (Polish
+ adaptation of the plain TeX format) package
+
+Some of these files may require adjustments to the needs
+of a particular system.
+
+The files in this directory are not the part of the EPSTOMF distribution,
+however, they belong to public domain (as far as we know), therefore we
+assumed that it is fair to include them here.
+
+-----------------------------------------------------------------------------
+
+END OF THE 0E2MFORM.DOC FILE
diff --git a/graphics/MF-PS/epstomf/e2mform/mft-pl.bat b/graphics/MF-PS/epstomf/e2mform/mft-pl.bat
new file mode 100644
index 0000000000..6ae9b11ec2
--- /dev/null
+++ b/graphics/MF-PS/epstomf/e2mform/mft-pl.bat
@@ -0,0 +1,15 @@
+@echo off
+:: mft-tex [par1] [par2] [par3] [par4]
+:: where
+:: [par1] = input file: 1%.mf
+:: [par2] = change file: 1%.mfc
+:: [par3] = style file: pl.mft
+:: [par4] = output file: 1%.tex
+if exist %1.mfc goto YEC
+:NOC
+mft %1.mf nul pl.mft %1.tex
+goto END
+:YEC
+mft %1.mf %1.mfc pl.mft %1.tex
+goto END
+:END
diff --git a/graphics/MF-PS/epstomf/e2mform/mftform.tex b/graphics/MF-PS/epstomf/e2mform/mftform.tex
new file mode 100644
index 0000000000..1a94a410f8
--- /dev/null
+++ b/graphics/MF-PS/epstomf/e2mform/mftform.tex
@@ -0,0 +1,61 @@
+% ---------------------------------------------------------------------------
+% This is an additional set of TeX macros for neat typesetting of METAFONT
+% documents produced by PS_CONV utility. It makes use of an archaic
+% Frank Mittelbach's multicolumn format adapted to plain TeX.
+% Also, PL.MFT from the MeX package should be used instead of PLAIN.MFT
+% from the standard TeX distribution. In order to use MFTFORM macros
+% you need to insert the following line
+% `%%\input mftform'
+% in your METAFONT source.
+% More information is not needed, as the user is supposed to be familiar with
+% Donald E. Knuth's MFT utility.
+% ---------------------------------------------------------------------------
+% Authors: B. Jackowski and P. Pianowski
+% ---------------------------------------------------------------------------
+% Version 1.0, Friday, November 3rd, 1995
+% ---------------------------------------------------------------------------
+% This little product belongs a public domain. No rights reserved.
+% ---------------------------------------------------------------------------
+\def\TI{\hbox{$\sim$}}
+\input mimulcol
+% ------------------------- MIMULCOL adjustments ----------------------------
+\newcount\COLS \COLS4 % default number of columns
+\def\EMU{\vfill\null\endmulticols}
+\def\BMU#1{\beginmulticols #1}
+{\catcode`\@11
+\gdef\adjust@PLAIN{%
+ \newlinechar=`\^^J
+ \columnwidth\hsize \textwidth\hsize
+ \@colht\vsize \@colroom\vsize % NO FLOATs PLEASE!
+ \def\makefootline{\baselineskip18pt\null\hrule\null\baselineskip12pt
+ \hbox to \textwidth{\it\oktime\quad \the\day\ \monthnazwa\ \the\year\
+ \hfill\llap{\tentex page \the\pageno}}}
+ \headline{\vbox to 0pt{\vss
+ \rlap{\hbox to \textwidth{\hss\TT\uppercase\expandafter{\jobname.mf}}}
+ \vskip5mm}\hss}
+ \def\pagebody{\vbox to\@colht{\boxmaxdepth\maxdepth \pagecontents}}
+ \def\vfootnote##1{\insert\footins\bgroup
+ \hsize=\textwidth
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \splitmaxdepth\dp\strutbox \floatingpenalty\@MM
+ \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+ \textindent{##1}\footstrut\futurelet\next\fo@t}
+ }
+}
+\vfuzz5pt \raggedcolumns \columnsep3pt
+% ------------------------- B E L M S formatting ----------------------------
+\let\ntwo\2
+\def\lB{B}\def\lE{E}\def\lL{L}\def\lM{M}\def\lS{S}
+\def\2#1{\def\twop{#1}%
+ \let\NEXT\ntwo
+ \ifx\twop\lB\let\NEXT\xtwo\fi
+ \ifx\twop\lE\let\NEXT\xtwo\fi
+ \ifx\twop\lL\let\NEXT\xtwo\fi
+ \ifx\twop\lM\let\NEXT\xtwo\fi
+ \ifx\twop\lS\let\NEXT\xtwo\fi
+\NEXT\twop}
+\newcount\xtwop
+\def\xtwo#1{\afterassignment\XTWO \xtwop = }
+\def\XTWO{\ntwo\twop_{\the\xtwop}}
+\endinput
diff --git a/graphics/MF-PS/epstomf/e2mform/mftmac.tex b/graphics/MF-PS/epstomf/e2mform/mftmac.tex
new file mode 100644
index 0000000000..3243e74d68
--- /dev/null
+++ b/graphics/MF-PS/epstomf/e2mform/mftmac.tex
@@ -0,0 +1,55 @@
+% special macros for use with MFT output
+
+\font\tenlogo=logo10 % font used for the METAFONT logo
+\font\tentex=cmtex10 \hyphenchar\tentex=-1 % font used for strings
+\font\sevenit=cmti7 \scriptfont\itfam=\sevenit
+\def\MF{{\tenlogo META}\-{\tenlogo FONT}}
+
+\parindent=0pt
+\thinmuskip=5mu
+\thickmuskip=6mu plus 6mu
+\mathcode`\|="326A
+
+\def\\#1{{\it#1}} % italic type for identifiers
+\def\0#1#2#3{\hbox{\rm\'{}\kern-.2em\it#1#2#3\/\kern.05em}} % octal constant
+\def\1#1{\mathop{\hbox{\rm#1}}} % operator, in roman type
+\def\2#1{\mathop{\hbox{\bf#1\/\kern.05em}}} % operator, in bold type
+\def\3#1{\,\mathclose{\hbox{\bf#1\/}}} % `fi' and `endgroup'
+\def\4#1{\mathbin{\hbox{\bf#1\/}}} % `step' and `at'
+\def\5#1{\hbox{\bf#1\/}} % `true' and `nullpicture'
+\def\6#1{\mathbin{\rm#1}} % `++' and `scaled'
+\def\7{\hbox\bgroup\nocats\frenchspacing\finstring} % string token
+\def\8#1{\mathrel{\mathcode`\.="8000 \mathcode`\-="8000
+ #1\unkern}} % `..' and `--'
+\def\9{\hfill$\%} % comment separator
+\def\?#1{\mathopen{#1}\;} % `:', `::', and `||:'
+\def\frac#1/#2{\leavevmode\kern.1em
+ \raise.5ex\hbox{\the\scriptfont0 #1}\kern-.1em
+ /\kern-.15em\lower.25ex\hbox{\the\scriptfont0 #2}}
+
+\mathchardef\AM="2026 % ampersand
+\let\BL=\medskip % space for empty line
+\mathchardef\BS="026E % backslash
+\mathchardef\HA="0222 % hat ("005E not as good)
+\def\PS{\mathbin{+{-}+}} % pythagorean subtraction
+\def\SH{\raise.7ex\hbox{$\scriptstyle\#$}} % sharp sign for sharped units
+\mathchardef\TI="007E % tilde
+
+\chardef\other=12
+\def\nocats{\catcode`\\=\other \catcode`\{=\other
+ \catcode`\}=\other \catcode`\$=\other \catcode`\&=\other
+ \catcode`\#=\other \catcode`\%=\other \catcode`\~=\other
+ \catcode`\_=\other \catcode`\^=\other}
+\def\finstring"#1"{\tentex"#1"\egroup}
+
+\newbox\shorthyf \setbox\shorthyf=\hbox{-\kern-.05em}
+\mathchardef\period=`\.
+{\catcode`\-=\active \global\def-{\copy\shorthyf\mkern3.9mu}
+ \catcode`\.=\active \global\def.{\period\mkern3mu}}
+
+\def\bf{\fam\bffam
+ \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}%
+ \tenbf}
+
+\def\join#1${} % say %%\join in .mf file to join lines together
+\def\]{\hskip0pt plus 1filll\ } % say % comment\] to get comment flush left
diff --git a/graphics/MF-PS/epstomf/e2mform/mimulcol.tex b/graphics/MF-PS/epstomf/e2mform/mimulcol.tex
new file mode 100644
index 0000000000..574b615675
--- /dev/null
+++ b/graphics/MF-PS/epstomf/e2mform/mimulcol.tex
@@ -0,0 +1,286 @@
+% copied from TUGboat, Vol.10 (1989) No.3 p.409--415 (B.J.)
+% MULTICOLUMN LaTeX environement.
+% Author: F. Mittelbach
+% Quick adaptation to PLAIN: B. Jackowski (Ver. 0.7); alterations are
+% marked by `(B.J.)'
+%
+% Since I do not understand floats I assume that they are
+% not used while multicolumning. Maybe some other day...
+%
+% ========================================================================
+% --------------------- PSEUDO-LaTeX ENVIRONEMENT ------------------------
+% ========================================================================
+\catcode`\@=11
+\newtoks\@uteroutput % (P.P.)
+\@uteroutput\output %
+% --------------------------
+\def\adjust@PLAIN{%
+ \newlinechar=`\^^J
+ \columnwidth\hsize \textwidth\hsize
+ \@colht\vsize \@colroom\vsize % NO FLOATs PLEASE!
+ \def\makefootline{\baselineskip24\p@\hbox to \textwidth{\the\footline}}
+ \def\pagebody{\vbox to\@colht{\boxmaxdepth\maxdepth \pagecontents}}
+ \def\vfootnote##1{\insert\footins\bgroup
+ \hsize=\textwidth
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \splitmaxdepth\dp\strutbox \floatingpenalty\@MM
+ \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+ \textindent{##1}\footstrut\futurelet\next\fo@t}
+}
+% --------------------------
+\mathchardef\@Mi=10001
+\newcount\@tempcnta % temporary count register
+% ------ These four macros differ from their LaTeX twins ------
+\def\thepage{\number\pageno}
+\def\addvspace#1{\vskip#1\relax}
+\def\typeout#1{\immediate\write\z@{#1}}
+\def\@warning#1{\typeout{WARNING: #1.}}
+% --------------------------
+\def\newpage{\par\vfil\penalty -\@M}
+\long\def\@ifundefined#1#2#3{\expandafter\ifx\csname
+ #1\endcsname\relax#2\else#3\fi}
+\def\@ifnextchar#1#2#3{\let\@tempe #1\def\@tempa{#2}\def\@tempb{#3}\futurelet
+ \@tempc\@ifnch}
+\def\@ifnch{\ifx \@tempc \@sptoken \let\@tempd\@xifnch
+ \else \ifx \@tempc \@tempe\let\@tempd\@tempa\else\let\@tempd\@tempb\fi
+ \fi \@tempd}
+\def\:{\let\@sptoken= } \: % this makes \@sptoken a space token
+\def\:{\@xifnch} \expandafter\def\: {\futurelet\@tempc\@ifnch}
+% --------------------------
+\def\@spaces{\space\space\space\space}
+\def\@width{width}
+\newdimen\@colroom
+\newdimen\@colht
+\newdimen\columnwidth
+\newdimen\textwidth
+% --------------------------
+\newdimen\columnsep \columnsep=24pt
+\newdimen\columnseprule \columnseprule = 0pt
+% ========================================================================
+% -------------------- MITTELBACH's MACROS -------------------------------
+% ========================================================================
+\newcount\unbalance \unbalance = 0
+\newcount\collectmore \collectmore = 0
+\newcount\tracingmulticols \tracingmulticols = 0
+\newcount\col@number
+\newcount\doublecol@number
+\newcount\multicoltolerance \multicoltolerance = 9999
+\newdimen\page@free
+\newdimen\premulticols \premulticols = 50pt
+\newdimen\postmulticols \postmulticols = 20pt
+\newskip\multicolsep \multicolsep = 12pt plus 4pt minus 3pt
+\newskip\multicolbaselineskip \multicolbaselineskip = 0pt
+\newbox\partial@page
+\newif\ifshr@nking
+%
+\@ifundefined{mult@cols}{}{\endinput}
+\ifnum\tracingmulticols>\z@ % <--------------------------------- added (B.J.)
+ \typeout{%
+ MULTI COLUMN format designed by Frank Mittelbach --- see TUGboat}
+ \typeout{%
+ Vol.10 (1989) No.3 pp.407--415> for doc.; PLAIN ver. 0.9 by B. Jackowski}
+\fi
+%
+\def\beginmulticols{\begingroup\multicols}% <--- substitute of LaTeX's phrase
+ % \begin{...} ... \end{...} (B.J.)
+%
+\def\multicols#1{\col@number#1\relax
+ %
+ \adjust@PLAIN
+ %
+ \ifnum\col@number<\@ne
+ \@warning{Using `number\col@number'
+ columns doesn't seem a good idea.^^J
+ \@spaces\@spaces I therefore use two columns instead}%
+ \col@number\tw@ \fi
+ \@ifnextchar[\mult@cols{\mult@cols[]}}
+%
+\def\mult@cols[#1]{\@ifnextchar[%
+ {\mult@@cols{#1}}%
+ {\mult@@cols{#1}[\premulticols]}}
+%
+\def\mult@@cols#1[#2]{%
+ \ifnum\tracingmulticols>\z@
+ \typeout{^^J^^JStarting multicolumn
+ output with \the\col@number
+ \space columns:^^J}\fi
+ \enough@room#2%
+ {#1}\par % <-------------- instead of #1\par---it seems more natural (B.J.)
+ % the more so, as outer {} braces inside [] brackets are gobbled:
+ % \multicols{...}[cosik] is equivalent to \multicols{...}[{cosik}]
+ \addvspace\multicolsep
+ \begingroup
+ \prepare@multicols\ignorespaces}
+%
+\def\enough@room#1{\par \penalty\z@
+ \page@free \pagegoal
+ \advance \page@free -\pagetotal
+ \ifnum \tracingmulticols>\z@
+ \typeout{Current page:}%
+ \message{\@spaces goal height=%
+ \the\pagegoal: used \the\pagetotal
+ \space -> free\the\page@free}%
+ \typeout{\@spaces needed \the#1
+ (for \string#1)}\fi
+ \ifdim \page@free <#1\newpage \fi}
+%
+\def\prepare@multicols{%
+ \output{\global\setbox\partial@page
+ \vbox{\unvbox\@cclv}}\eject
+ \vbadness9999 \hbadness5000
+ \tolerance\multicoltolerance
+ \doublecol@number\col@number
+ \multiply\doublecol@number\tw@
+ \advance\baselineskip\multicolbaselineskip
+ \advance\@colroom-\ht\partial@page
+ \vsize\col@number\@colroom
+ \advance\vsize\collectmore\baselineskip
+ \hsize\columnwidth \advance\hsize\columnsep
+ \advance\hsize-\col@number\columnsep
+ \divide\hsize\col@number
+% \linewidth\hsize % <----------------- it seems unnecessary in PLAIN (B.J.)
+ \output{\multi@columnout}%
+ \multiply\count\footins\col@number
+ \multiply\skip \footins\col@number
+ \reinsert@footnotes}
+%
+\def\endmulticols{\par\penalty\z@
+ \output{\balance@columns}\eject
+ \endgroup \reinsert@footnotes
+ \global\unbalance\z@
+ \enough@room\postmulticols
+ \addvspace\multicolsep
+ \nointerlineskip % <------------------------------------------ added (B.J.)
+ \ifnum \tracingmulticols>\z@
+ \typeout{^^JEnding multicolumn
+ output.^^J^^J}\fi
+ \endgroup}
+%
+\def\process@cols#1#2{\count@#1\relax
+ \loop #2%
+ \advance\count@\tw@
+ \ifnum\count@<\doublecol@number
+ \repeat}
+%
+\def\page@sofar{\unvbox\partial@page
+ \process@cols\z@{\wd\count@\hsize}%
+ \hbox to \textwidth{%
+ \process@cols\tw@{\box\count@
+ \hss\vrule\@width\columnseprule\hss}%
+ \box\z@}}
+%
+\def\reinsert@footnotes{\ifvoid\footins\else
+ \insert\footins{\unvbox\footins}\fi}
+%
+\def\multi@columnout{%
+ \ifnum\outputpenalty <-\@Mi
+ \speci@ls
+ \else
+ \splittopskip\topskip
+ \splitmaxdepth\maxdepth
+ \dimen@\@colroom
+ \divide\skip\footins\col@number
+ \ifvoid\footins \else
+ \advance\dimen@-\skip\footins
+ \advance\dimen@-\ht\footins \fi
+ \process@cols\tw@{\setbox\count@
+ \vsplit\@cclv to\dimen@}%
+ \setbox\z@\vsplit\@cclv to\dimen@
+ \ifvoid\@cclv \else
+ \unvbox\@cclv
+ \penalty\outputpenalty
+ \ifnum \tracingmulticols>\tw@
+ \hrule\allowbreak \fi
+ \ifvoid\footins\else % <----------------------------------- added (B.J.)
+ \@warning{I moved some lines to the next page.^^J
+ \@spaces\@spaces Footnotes on page \thepage\space
+ might be wrong}\fi\fi
+ \setbox\@cclv\vbox{\page@sofar}%
+% \plainoutput % <---------------- instead of \@makecol\@outputpage (B.J.)
+ \the\@uteroutput % <------------- instead of \plainoutput (P.P.)
+ \global\@colroom\@colht
+ \process@deferreds
+ \ifnum\tracingmulticols>\@ne
+ \typeout{Colroom: \the\@colht\space after float
+ space removed = \the\@colroom}\fi
+ \global\vsize\col@number\@colroom
+ \global\advance\vsize \collectmore\baselineskip
+ \multiply\skip\footins\col@number
+ \fi}
+%
+\def\speci@ls{%
+ \typeout{Floats and marginpars not allowed inside
+ `multicols' environement!}%
+ \unvbox\@cclv\reinsert@footnotes
+% \gdef\@currlist{}% <----------------------------- not used in PLAIN (B.J.)
+ }
+%
+\def\process@deferreds{}% <---------- instead of the `percented' macro (B.J.)
+ % (temporarily: until I'll learn what all that
+ % mumbling means)
+%\def\process@deferreds{%
+% \@floatplacement
+% \begingroup
+% \let\@tempb\@deferlist
+% \gdef\@deferlist{}%
+% \let\@elt\@scoelt
+% \@tempb \endgroup}
+%
+% Originally: <------------------------------------------------------- (B.J.)
+%\def\raggedcolumns{\@bsphack\shr@nkingtrue\@esphack}
+%\def\flushcolumns{\@bsphack\shr@nkingfalse\@esphack}
+%
+\def\raggedcolumns{\shr@nkingtrue}
+\def\flushcolumns{\shr@nkingfalse}
+%
+\def\balance@columns{%
+ \splittopskip\topskip
+ \splitmaxdepth\maxdepth
+ \setbox\z@\vbox{\unvbox\@cclv}\dimen@\ht\z@
+ \advance\dimen@ \col@number\topskip
+ \advance\dimen@ -\col@number\baselineskip
+ \divide\dimen@ \col@number
+ \advance\dimen@ \unbalance\baselineskip
+ \ifnum\tracingmulticols>\@ne
+ \typeout{Balance columns: \ifnum\unbalance=\z@\else
+ (off balance=\number\unbalance)\fi}%
+ \fi
+ {\vbadness\@M
+ \loop
+ {\process@cols\@ne{\global\setbox\count@\box\voidb@x}}%
+ \global\setbox\@ne\copy\z@
+ {\process@cols\thr@@{\global\setbox\count@
+ \vsplit\@ne to\dimen@}}%
+ %
+ % ... After \process@cols has done its job we have the following situation:
+ % box0 <-- all material
+ % box3 <-- first column
+ % box5 <-- second column
+ % ...
+ % box1 <-- last column ...
+ %
+ \ifnum\tracingmulticols>\@ne
+ \message{\@spaces First column = \the\ht\thr@@}\fi
+ \ifshr@nking \global\setbox\thr@@\vbox{\unvbox\thr@@}%
+ \ifnum\tracingmulticols>\@ne
+ \message{ after shrinking \the\ht\thr@@}\fi\fi
+ \ifnum\tracingmulticols>\@ne
+ \message{<> last column = \the\ht\@ne}%
+ \typeout{}\fi
+ \ifdim\ht\@ne > \ht\thr@@
+ \global\advance\dimen@\p@
+ \repeat}%
+ \dimen@\ht\thr@@
+ \process@cols\z@{\@tempcnta\count@
+ \advance\@tempcnta\@ne
+ \setbox\count@\vtop to\dimen@
+ {\unvbox\@tempcnta
+ \ifshr@nking\vfill\fi}}%
+ \global\vsize\@colroom
+ \global\advance\vsize\ht\partial@page
+ \page@sofar}
+% ========================================================================
+\catcode`\@=12 % default PLAIN value
+% ========================================================================
+\endinput
diff --git a/graphics/MF-PS/epstomf/e2mform/pl.mft b/graphics/MF-PS/epstomf/e2mform/pl.mft
new file mode 100644
index 0000000000..00f4f67269
--- /dev/null
+++ b/graphics/MF-PS/epstomf/e2mform/pl.mft
@@ -0,0 +1,111 @@
+%%%% MFT style for the Polish extension of Computer Modern (PL fonts)
+%%%% CMBASE style:
+%%% } ( ) ]] {{ }} ! ^ %%%% tokens that need no special formatting
+%%% step upto downto %%%% boldface binary operators
+%%% addto fill unfill draw undraw %%%% boldface unary operators
+%%% addto filldraw unfilldraw drawdot undrawdot erase pickup
+%%% addto exitunless stop incr decr proofrulethickness screenrule
+%%% addto define_pixels define_whole_pixels define_whole_vertical_pixels
+%%% addto define_blacker_pixels define_whole_blacker_pixels
+%%% addto define_corrected_pixels lowres_fix proofoffset penstroke
+%%% addto beginchar beginarithchar italcorr font_size font_slant
+%%% addto font_normal_space font_normal_stretch font_normal_shrink font_quad
+%%% addto font_x_height font_extra_space font_identifier font_coding_scheme
+%%% addto cmchar iff generate adjust_fit math_fit labels penlabels
+%%% addto stroke circ_stroke padded
+%%% enddef endchar %%%% boldface closing
+%%% true relax mode_setup font_setup %%%% boldface nullary operators
+%%% true clearit shipit cullit openit showit clearxy clearpen
+%%% true nodisplay notransforms screenchars screenstrokes imagerules
+%%% .. ... .... -- --- %%%% path operators made of dots and dashes
+%%% length flex abs dir %%%% unary operators to be in roman type
+%%% length unitvector inverse ceiling hround vround Vround counterclockwise
+%%% length tensepath byte reflectedabout rotatedaround magstep max min
+%%% and mod dotprod intersectionpoint softjoin %%%% binary operators to be roman
+%%% ++ ** %%%% binary operators made of two special characters
+%%% penoffset goodval direction directionpoint %%%% operators that take "of"
+%%% pausing tolerance pixels_per_inch blacker o_correction %%%% internals
+%%% pausing screen_rows screen_cols currentwindow displaying
+%%% pausing pen_top pen_bot pen_lft pen_rt shrink_fit rt lft top bot
+%%% = <= >= <> %%%% conversions for the SAIL character set only
+%%% good crisp fine tiny rule light_rule cal light_cal med_cal heavy_cal
+%%% good term fudged mfudged sloped_serif tilted med_tilted
+%%% pausing slant fudge math_spread superness superpull beak_darkness ligs
+%% \outer\def^^L{\par\vfill\eject} % obeypages
+%%%%-------------------------------------------------------------------------
+%%%% So far it was CMBASE; now
+%% %--------- BJ & MR predilections & idiosyncrasies (ver. 1.03) ------------
+%%%% follow:
+%%%%-------------------------------------------------------------------------
+%%% end bye %%%% end=bye, isn't it?
+%%% screenrule proofrule %%%% proofrule=screenrule, isn't it?
+%%% def mode_def %%%% def=mode_def, isn't it?
+%%% input generate %%%% input=generate, isn't it?
+%%% for range %%%% we prefere \MF{}book convention
+%%% step thru %%%% ditto
+%%% good lower
+%%%%-------------------------------------------------------------------------
+%%%% our slight modifications:
+%%\newcount\hours \newcount\minutes
+%%\ifx\plconventions\undefined %%%% don't define some dangerous macros twice
+%%%%-------------------------------------------------------------------------
+%%\let\plconventions\relax
+%%\def\MeX{M\kern-.111em\lower.5ex\hbox{E}\kern-.125emX}
+%%\let\OSH\#
+%%\def\SH{\raise.7ex\hbox{$\scriptstyle\OSH$}} % sharp sign for sharped units
+%%\let\#\SH \def\\#1{{\let\#\OSH\it#1}}
+%%\def\finstring"#1"{\tentex"#1"\egroup}
+%%\def\frac#1/#2{\leavevmode\kern.1em
+%% \raise.5ex\hbox{\the\scriptfont0 #1}\kern-.1em
+%% /\kern-.15em\lower.25ex\hbox{\the\scriptfont0 #2}\,} %%%% \, added
+%%\let\UL\_
+%%\def\_{\ifdim\fontdimen1\the\font=0pt \UL\kern0.01em\else\kern-0.08em\UL\kern0.04em\fi}
+%%%%-------------------------------------------------------------------------
+%%%% our string treatment:
+%%\font\ttfont pltt10
+%%\def\vispace{{\ttfont\char32}}
+%%%% strings may be broken in a .TeX file:
+%%{\obeyspaces\obeylines%
+%%\gdef\prepspnl{\obeyspaces\obeylines\let \vispace\let^^M\vispace}}
+%%\def\7{\hbox\bgroup\prepspnl\nocats\frenchspacing\finstring} % string token
+%%%%-------------------------------------------------------------------------
+%%%% our comment treatment:
+%%\font\commfont plsltt10 % standard comment font
+%%\font\bif plbxti10 % comment bold italic font
+%%%% sorry, but we're using the UNderSCOre in COmments (see the dirty trick)
+%%\def\unscoco{\ifmmode_\else\_\fi} \catcode`\_\active \let_\unscoco
+%%\font\trifnt plmib10 scaled \magstep2 \def\lftri{{\trifnt \char'57}}
+%%{\obeyspaces\gdef\prepsp{\obeyspaces\everymath{\catcode`\ 10\relax}\let \ }}
+%%\fi %%%% no more dangerous macros
+%%\def\specialcomments{%
+%% \def\9{$\bgroup\def\par{\hfill\lftri\endgraf\egroup}\commfont\%\prepsp}}
+%%\def\normalcomments{%
+%% \def\9{$\bgroup\def\par{\endgraf\egroup}\hfill\commfont\%\prepsp}}
+%%\specialcomments % our favorite form of comments
+%%%%-------------------------------------------------------------------------
+%%%% DIRTY TRICK---sorry, but we're also using the underscore in file names
+%%%% (assumption: \tt appears only as \hbox{\tt...})
+%%\def\tt{\nocats\namett}
+%%{\catcode`\}\other \catcode`\)2\gdef\namett#1}{\tentex#1\egroup))
+%%%%-------------------------------------------------------------------------
+%%%% our footline:
+%%\def\oktime{% format `hh:mm'
+%%\hours=\time \divide \hours by 60 %
+%%\minutes=-\hours \multiply \minutes by 60 \advance \minutes by \time
+%%\ifnum\hours>9 \the\hours \else 0\the\hours \fi
+%%:%
+%%\ifnum\minutes>9 \the\minutes \else 0\the\minutes \fi}
+%%\def\monthnazwa{\ifcase \month
+%%\or stycznia\or lutego\or marca\or kwietnia\or maja\or czerwca\or lipca%
+%%\or sierpnia\or wrze\'snia\or pa\'zdziernika\or listopada\or grudnia%
+%%\fi}
+%%\def\makefootline{\baselineskip18pt\null\hrule\null\baselineskip12pt
+%% \line{\it\oktime\quad \the\day\ \monthnazwa\ \the\year\
+%% \hfill\llap{\tentex page \the\pageno}}}
+%%%%-------------------------------------------------------------------------
+%%%% our headline:
+%%\font\TT pltt12 scaled\magstep2
+%%\headline{\vbox to 0pt{\vss
+%% \rightline{\TT\uppercase\expandafter{\jobname.mf}}\vskip5mm}}
+%% %-------------------------------------------------------------------------
+
diff --git a/graphics/MF-PS/epstomf/epstomf.awk b/graphics/MF-PS/epstomf/epstomf.awk
new file mode 100644
index 0000000000..163a4ecd14
--- /dev/null
+++ b/graphics/MF-PS/epstomf/epstomf.awk
@@ -0,0 +1,375 @@
+# ---------------------------------------------------------------------------
+# This file belongs to the EPSTOMF package.
+# ---------------------------------------------------------------------------
+# You are entitled to do with the file whatever you wish. If you alter a file,
+# however, please remove the line containing the comment:
+#
+# `This file belongs to the EPSTOMF package.'
+#
+# in order to avoid mess.
+# ---------------------------------------------------------------------------
+# AUTHORS: B. Jackowski, P. Pianowski, M. Ry\'cko
+# HISTORY:
+# version 0.50: Tuesday, August 15th, 1995
+# * first less or more complete version
+# version 0.51: Monday, October 23rd, 1995
+# * comments adjusted to a new distribution
+# version 0.52: Monday, November 6th, 1995
+# * miter limit is a dimensionless quantity
+# version 0.53: Wednesday, March 19th, 1997
+# * degenerated (single-node) paths used to be processed improperly
+# * font dimens specified explicitly
+# * `plain' option added (a METAFONT code without referring to the
+# MFTOEPS package is generated if variable `plain' is set to 1)
+# version 0.54: Thursday, January 29th, 1998
+# * this and previous versions were stimulated (stipulated in fact :-)
+# by Samy Alex Za\"\i{}mi -- thanks!
+# * all kinds of end-of-line characters are accepted in
+# input files; this, however, necessitates using Gnu AWK
+# * a patch was added to cope (somehow) with PageDraw's (ver. 2.0)
+# EPSes that do not conform to the definition of a ``canonical''
+# EPS given below, nonetheless, they are ``nearly canonical''
+# and something can be done
+# * in order to avoid annoying gftodvi's messages
+# ``Too many labels'' and ``Too many labels and/or rules''
+# the command |labels| is preceded by a percent sign if
+# suspiciously many nodes occur
+# ---------------------------------------------------------------------------
+# This is an AWK program for the translation of a ``canonical'' (see below)
+# EPS file into METAFONT lingo; the resulting METAFONT program inputs MFTOEPS
+# macros (ver. >= 0.61). EPS files created using the MFTOEPS package are
+# accepted by this converter.
+# ---
+# The crucial features of a ``canonical'' EPS file are listed below:
+# 0. General assumptions:
+# a) parameters of a command appear in one line along with the command;
+# b) only explicit numerical values are admissible (variables are not
+# interpreted);
+# c) all numbers are expressed in PostScript points (called in TeX
+# ``big points'': 1/72in), i.e., no local transformations are involved;
+# d) prior to painting a curve (fill or stroke) its parameters
+# for filling or stroking are explicitly set;
+# e) only the commands listed in items 1--11 are interpreted.
+# 1. `gsave' and `grestore' are represented by `q' and `Q', respectively;
+# malformed grouping structure may yield unpredictable results.
+# 2. `moveto' is represented by `m'.
+# 3. `lineto' is represented by either `l' or `L'.
+# 4. `curveto' is represented by either `c' or `C'.
+# 5. `setlinewidth' is represented by `w'.
+# 6. `setlinejoin' is represented by `j'.
+# 7. `setlinecap' is represented by `J'.
+# 8. `setmiterlimit' is represented by `M'.
+# 9. `setdash' is represented by `d'.
+# 10. Curves start with `*u' and end with `*U'; no `q'/`Q' commands are
+# expected to occur inside a curve, i.e., between `*u' and `*U' commands;
+# `q'/`Q' pairs occuring outside a curve, i.e., between `*U' and `*u'
+# commands, are ignored; actually, the latter situation should not
+# occur either.
+# 11. Component paths of a multi-path curve end consistently either
+# with `f' (filling), or `s'/`S' (stroking of closed and open paths,
+# resp.), or `h W n' (clipping; in fact, only `n' is taken taken into
+# account).
+# 12. Structural comments `%%BoundingBox' and `%%EndSetup' should occur at
+# the beginning of the file (in this order).
+# ---
+# COMMENTS:
+# 1. The engine works in such a way that at first a necessary information
+# about paths is collected; during this stage only the coordinates of
+# nodes are written; after processing all the data the ``painting'' code
+# is generated; this complicates the AWK code a bit due to controlling
+# `gsave'/`grestore' nesting; a simplified approach is used: instead of
+# recording the full nesting tree, a ``backbone'' of a nesting structure
+# is reconstructed (cf. item 10 above).
+# 2. A little bit more complicated (in comparison with other commands) is
+# the translation of `d' (`setdash') command; in addition to the
+# assumptions specified above, it is assumed that at least one space
+# precedes `[' and `d', and follows `]'.
+# 3. Some complexity is also involved at the METAFONT level at the stage of
+# computing of a bounding box; as a default, the graphic object is shifted
+# such that the left lower corner of the bounding box coincides with
+# the origin of the coordinate system; by manual alteration of the
+# resulting METAFONT file the user can easily control the situation, e.g.,
+# vertical or horizontal shift (or both) can be prohibited, the original
+# bounding box can be preserved, etc.; one should also remember that
+# if clipping is involved, the computed bounding box may be invalid.
+# 4. Due to rounding errors the original EPS file and the EPS file generated
+# from a resulting METAFONT file may differ.
+# ---------------------------------------------------------------------------
+BEGIN {
+ skipping=1
+ path_max=0
+ group_max=0
+ node_max=0
+ xl=0; yl=0; xh=72; yh=72; # emergency default
+# `q'/`Q' nesting is controled by the following three variables
+# (`ignore_grestore' controls ignoring `q'/`Q' pairs between curves):
+ nesting_level=0; nesting_group=0; ignore_grestore=0
+ RS="\015|\012|\015\012"
+}
+# ---
+(skipping==1) && ($0 ~ /^%%BoundingBox:/) {xl=$2; yl=$3; xh=$4; yh=$5}
+# ---
+(skipping==1) && $0=="%%EndSetup" {skipping=0;
+ print "%%% fill fill_C draw_C clip_C set_BB find_BB close_path"
+ print "%%% fill fix_fill_cmyk fix_draw_cmyk"
+ print "%%% fill fix_line_width fix_line_join fix_line_cap"
+ print "%%% fill fix_miter_limit fix_dash"
+ print "%%% message write_preamble"
+ print "%%% endchar write_postamble g_save g_restore"
+ print "%%% addto ~"
+ print "%%\\input mftform"
+ if (!plain) print "input mftoeps;"
+ print "numeric w#, h#, d#, xl#, yl#, xh#, yh#, xs#, ys#;"
+ print "xl#=" xl "bp#; yl#=" yl "bp#; xh#=" xh "bp#; yh#=" yh "bp#;";
+ print "if false: noxs:=0; fi % no horizontal shift, ignored by default"
+ print "if false: noys:=0; fi % no vertical shift, ignored by default"
+ if (!plain) {
+ print "if false: oribb:=0; fi",
+ "% preserving the original bounding box, ignored by default"
+ print "pinbb:=0; % default: shifting the object such that |(xl,yl)=(0,0)|"
+ }
+ print "xs#=if known noxs: 0 else: -xl# fi;"
+ print "ys#=if known noys: 0 else: -yl# fi;"
+ print "w#=max(0,xh#+xs#); h#=max(0,yh#+ys#); d#=max(0,-yl#-ys#);"
+ print "%"
+ fn=FILENAME; gsub(/^.*[\/\\]/,"",fn); gsub(/\.[^\/\\]*$/,"",fn)
+ print "font_identifier:=\"" fn "\";";
+ print "font_size round(w#);"
+ print "font_slant 0;"
+ print "font_normal_space w#;"
+ print "font_normal_stretch 0;"
+ print "font_normal_shrink 0;"
+ print "font_x_height h#;"
+ print "font_quad w#;"
+ print "font_extra_space 0;"
+ print "message \"The font size = \" & decimal(designsize) & \"pt#\";"
+ print "message \"\";"
+ print "%"
+ if (!plain) print "extra_eps_setup:=\"pixels_per_inch:=72\";",
+ "% better resolution for this case"
+ print (plain ? "" : "eps_") "mode_setup; define_pixels(xs, ys);"
+ print "%"
+ print "def ~ text xy = \\\\ = (bp*xpart(xy)+xs,bp*ypart(xy)+ys) enddef;"
+ print "%%% step C B L M"
+ print "def M = M_ ( enddef;"
+ print "def M_(suffix $) = z$ enddef;"
+ print "def B = ) B_ ( enddef;"
+ print "def B_(suffix $) = .. controls z$a and z$b .. z$ enddef;"
+ print "def L = ) L_ ( enddef;"
+ print "def L_(suffix $) = -- z$ enddef;"
+ print "def C = ) enddef;"
+ print "def close_path suffix p ="
+ print " p:=p if (point 0 of p)=(point length(p) of p): & else: -- fi cycle;"
+ print "enddef;"
+ print "%%% labels B L M"
+ print "%%% fi C"
+ if (plain) {
+ print "% ---"
+ print "def eofill expr P ="
+ print " begingroup save pp_; picture pp_;"
+ print " interim turningcheck:=0;"
+ print "% the following |addto|s are supposed to fill disjoint areas:"
+ print " pp_:=nullpicture; addto pp_ contour P.t_;"
+ print " cull pp_ keeping (1,infinity); addto currentpicture also pp_;"
+ print " pp_:=nullpicture; addto pp_ contour reverse P.t_;"
+ print " cull pp_ keeping (1,infinity); addto currentpicture also pp_;"
+ print " cull currentpicture keeping(1,1);"
+ print " endgroup"
+ print "enddef;"
+ print "def fill_C text t ="
+ print " begingroup"
+ print " save rr_; picture rr_; % must not be |pp_| (see |eofill|)"
+ print " begingroup"
+ print " save currentpicture; def currentpicture = rr_ enddef; % danger!"
+ print " currentpicture:=nullpicture; for qq_:=t: eofill qq_; endfor"
+ print " endgroup;"
+ print " addto currentpicture also rr_; cullit;"
+ print " endgroup"
+ print "enddef;"
+ print "def draw_C text t = for pp_:=t: draw pp_; endfor enddef;"
+ print "def clip_C text t = enddef;"
+ }
+ print "% ---"
+ print "beginchar("0",w#,h#,d#); path p[\\\\];"
+}
+# ---
+skipping==0 {
+ for (i=1; i<=NF; i+=1) {
+# ---
+ if ($i=="q") {++nesting_level; ++ignore_grestore}
+# ---
+ if ($i=="Q") {
+ --nesting_level
+ if (ignore_grestore>0) {--ignore_grestore} else {++nesting_group}
+ }
+# ---
+ if ($i=="*u") {
+ print ""; print "% BEGIN of GROUP", group_max ";"
+ ignore_grestore=0; first_path[group_max]=path_max
+ }
+# ---
+ if ($i=="k") {
+ fix_fill_cmyk[group_max]=$(i-4) "," $(i-3) "," $(i-2) "," $(i-1)
+ }
+# ---
+ if ($i=="K") {
+ fix_draw_cmyk[group_max]=$(i-4) "," $(i-3) "," $(i-2) "," $(i-1)
+ }
+# ---
+ if ($i=="w") fix_line_width[group_max]=$(i-1) "bp"
+# ---
+ if ($i=="j") fix_line_join[group_max]=$(i-1)
+# ---
+ if ($i=="J") fix_line_cap[group_max]=$(i-1)
+# ---
+ if ($i=="M") fix_miter_limit[group_max]=$(i-1)
+# ---
+ if ($i=="d") {# this is a little bit more complex case (see comment 2)
+ l=i-2; # $(i-1)="d", $(i-1) is the offset
+ for (j=l; $j !~ /\[/; --j) {}
+# $j contains the opening bracket for `setdash'
+# $l contains the closing bracket for `setdash'
+ gsub(/\[/,"",$j); gsub(/\]/,"",$l) # delete both brackets
+ was_something=0
+ fix_dash[group_max]="("; # construct parameters for `fix_dash'
+ for (k=j; k<=l; ++k) {
+ if ($k != "") {
+ if (was_something==1) {aux=","} else {was_something=1; aux=""}
+ fix_dash[group_max]=fix_dash[group_max] aux $k "bp"
+ }
+ }
+ fix_dash[group_max]=fix_dash[group_max] ") " $(i-1) "bp"
+ }
+# ---
+ if ($i=="m") {
+ print "% begin of path", path_max ";"
+ print "%%\\BMU\\COLS"
+ print "z" node_max "~" $(i-2) "," $(i-1) ";"
+ node_path[node_max]=path_max; first_node[path_max]=node_max; ++node_max
+ }
+# ---
+ if (($i=="l") || ($i=="L")) {
+ print "z" node_max "~" $(i-2) "," $(i-1) ";"
+ node_path[node_max]=path_max; arc_type[node_max]="L"; ++node_max
+ }
+# ---
+ if (($i=="c") || ($i=="C")) {
+ print "z" node_max "a~" $(i-6) "," $(i-5) ";"
+ print "z" node_max "b~" $(i-4) "," $(i-3) ";"
+ print "z" node_max "~" $(i-2) "," $(i-1) ";"
+ node_path[node_max]=path_max; arc_type[node_max]="B"; ++node_max
+ }
+# ---
+ if (($i=="f") || ($i=="s") || ($i=="S") || ($i=="n")) {
+ print "%%\\EMU";
+ path_group[path_max]=group_max; last_node[path_max]=node_max-1;
+ group_type[group_max]=$i; # should be consistent for all paths in a group
+ if (($i=="f") || ($i=="s") || ($i=="n")) is_closed_path=1
+ else is_closed_path=0
+ aux="p" path_max "=M" first_node[path_max]
+ if (first_node[path_max]<last_node[path_max])
+ for (j=first_node[path_max]+1; j<=last_node[path_max]; ++j) {
+ aux=aux " " arc_type[j] j
+ if (j==last_node[path_max]) aux=aux " C;"
+ if (length(aux)>70) {print aux; aux=""}
+ } else aux=aux " C;" # degenerated case
+ if (aux!="") print aux
+ if (is_closed_path==1) print "close_path p" path_max ";"
+ print "% end of path", path_max ";"
+ ++path_max
+ }
+# ---
+ if ($i=="*U") {
+ print "% END of GROUP", group_max ";";
+ group_nesting_level[group_max]=nesting_level;
+ group_nesting_group[group_max]=nesting_group;
+ last_path[group_max]=path_max-1;
+ ++group_max
+ }
+ }
+}
+# ---
+END {
+ node_max--
+ path_max--
+ group_max--
+# ---
+ if (!plain) {
+ print ""
+ print "if known oribb:"
+ print " set_BB " xl "bp+xs," yl "bp+ys," xh "bp+xs," yh "bp+ys;"
+ print "elseif known pinbb:"
+ print " find_BB p0 for i:=1 upto " path_max": , p[i] endfor;"
+ print " for i:=0 upto " node_max":"
+ print " x[i]:=x[i]-xl_crd; y[i]:=y[i]-yl_crd;"
+ print " if known x[i]a: x[i]a:=x[i]a-xl_crd; fi"
+ print " if known x[i]b: x[i]b:=x[i]b-xl_crd; fi"
+ print " if known y[i]a: y[i]a:=y[i]a-yl_crd; fi"
+ print " if known y[i]b: y[i]b:=y[i]b-yl_crd; fi"
+ print " endfor"
+ print " for i:=0 upto " path_max": p[i]:=p[i] shifted -llxy; endfor"
+ print " set_BB origin, urxy-llxy;"
+ print "else:"
+ print " find_BB p0 for i:=1 upto " path_max": , p[i] endfor;"
+ print "fi"
+ print "write_preamble jobname;"
+ }
+# ---
+# one extra `gsave'/`grestore' pair is always added by MFTOEPS, hence `-2'
+ if (!plain) for (j=0; j<=group_nesting_level[0]-2; ++j) {print "g_save;"}
+ for (g=0; g<=group_max; ++g) {
+ if (plain) {
+ if (fix_line_width[g]!="")
+ print "pickup pencircle scaled " fix_line_width[g] ";"
+ } else {
+ if (g>0) {
+ k=group_nesting_group[g]-group_nesting_group[g-1];
+ # k == number of groups closed in the meantime
+ for (j=1; j<=k; ++j) print "g_restore;"
+ k=group_nesting_level[g-1]-k; l=group_nesting_level[g];
+ # k == current nesting level, l == resulting nesting level
+ for (j=1; j<=(k-l); ++j) print "g_restore;"
+ for (j=-1; j>=(k-l); --j) print "g_save;"
+ }
+ if (fix_fill_cmyk[g]!="") print "fix_fill_cmyk " fix_fill_cmyk[g] ";"
+ if (fix_draw_cmyk[g]!="") print "fix_draw_cmyk " fix_draw_cmyk[g] ";"
+ if (fix_line_width[g]!="") print "fix_line_width " fix_line_width[g] ";"
+ if (fix_line_join[g]!="") print "fix_line_join " fix_line_join[g] ";"
+ if (fix_line_cap[g]!="") print "fix_line_cap " fix_line_cap[g] ";"
+ if (fix_miter_limit[g]!="") print "fix_miter_limit " fix_miter_limit[g] ";"
+ if (fix_dash[g]!="") print "fix_dash " fix_dash[g] ";"
+ }
+ if (group_type[g]=="f") aux="fill_C"
+ if ((group_type[g]=="s") || (group_type[g]=="S")) aux="draw_C"
+ if (group_type[g]=="n") aux="clip_C"
+ for (j=first_path[g]; j<=last_path[g]; ++j) {
+ aux=aux " p" j (j==last_path[g] ? ";" : ",")
+ if (length(aux)>70) {print aux; aux=""}
+ }
+ if (aux!="") print aux
+ }
+# ---
+ if ((group_max<0) && (path_max>0)) {
+# something went wrong (non-conforming EPS?);
+# let's undertake a desperate defense of the nearly wasted task:
+ g=0; aux="fill_C" # emergency initialization
+ if (group_type[g]=="f") aux="fill_C"
+ if ((group_type[g]=="s") || (group_type[g]=="S")) aux="draw_C"
+ if (group_type[g]=="n") aux="clip_C"
+ for (j=0; j<=path_max; ++j) {
+ aux=aux " p" j (j==path_max ? ";" : ",")
+ if (length(aux)>70) {print aux; aux=""}
+ }
+ if (aux!="") print aux
+ }
+# ---
+# one extra `gsave'/`grestore' pair is always added by MFTOEPS, hence `-2'
+ for (j=0; j<=group_nesting_level[group_max]-2; ++j) print "g_restore;"
+ if (!plain) print "write_postamble;"
+ # not to many nodes please (otherwise gftodvi is likely to break down):
+ print (node_max>800 ? "% " : "") "labels(range" 1 "thru" node_max ");"
+ print "endchar;"
+ print "% ---"
+ print "end."
+ print "%%\\end"
+}
diff --git a/graphics/MF-PS/mftoeps/0mftoeps.doc b/graphics/MF-PS/mftoeps/0mftoeps.doc
new file mode 100644
index 0000000000..4edfd06cd3
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/0mftoeps.doc
@@ -0,0 +1,218 @@
+This file belongs to the MFTOEPS package.
+
+-----------------------------------------------------------------------------
+
+OVERVIEW
+
+The package MFTOEPS belongs to the public domain. You are entitled to do with
+the files of which it consists whatever you wish. If you alter a file,
+however, please remove the line containing the comment
+
+ `This file belongs to the MFTOEPS package.'
+
+in order to avoid a mess.
+
+The kernel of this little package is the METAFONT program MFTOEPS.MF written
+by Bogus\l{}aw Jackowski, Piotr Pianowski and Marek Ry\'cko. The aim of the
+program is to produce EPS (encapsulated PostScript) files readable by
+CorelDRAW!(R), Adobe Illustrator(TM) and Fontographer(R).
+
+The user of the package is supposed to be familiar a bit with METAFONT and
+PostScript. Donald E. Knuth's ``The METAFONTbook'' and Adobe's ``PostScript
+Language Reference Manual'' (both by Addison-Wesley Publishing Company, Inc.)
+should be consulted in the case of doubts.
+
+There is a bunch of simple examples in the subdirectory M2ESAMP. The
+directory ../PROGS contains DOS batch files and other programs which,
+possibly after some adjustments, can be used to generate EPS files.
+
+Roughly, the machinery works as follows: the resulting PostScript code
+is written by METAFONT to a LOG file; the LOG file is then processed
+either by AWK or by TeX (see the PROGS subdirectory) in order to extract
+the PostScript code. The idea seems straightforward; however, even
+a partial conciliation of the worlds of CorelDRAW! and Adobe Illustrator
+was not so much straightforward.
+
+-----------------------------------------------------------------------------
+
+In addition to the main MFTOEPS package, there are two ``bonus'' packages in
+directories ../EPSTOMF and ../ROEX. EPSTOMF converts ``canonical'' EPS files,
+i.e., files conforming the structure of the files generated by the MFTOEPS
+package, into the METAFONT lingo; ROEX is a set of METAFONT macros
+accomplishing the task of removing overlaps and expanding strokes (for
+details see there).
+
+-----------------------------------------------------------------------------
+
+INTERFACE SYNOPSIS
+
+Conventions: In the following we shall use words `number,' `pair,' `string,'
+and `path' as an abbreviation for `numeric expression,' `pair expression,'
+`string expression,' and `path expression,' respectively. The signs `less'
+and `greater,' used for marking parameters of macros, are
+``meta-characters,'' i.e., they do not belong to the METAFONT code.
+
+There are fifteen interface macros defined in the MFTOEPS.MF file:
+ eps_mode_setup
+ write_preamble
+ write_postamble
+ set_BB
+ find_BB
+ reset_BB
+ fill_C
+ draw_C
+ clip_C
+ fix_line_width
+ fix_line_join
+ fix_line_cap
+ fix_line_miter_limit
+ fix_fill_cmyk
+ fix_draw_cmyk
+
+COMMAND eps_mode_setup
+USAGE eps_mode_setup <an optional number (0 or 1)>;
+REMARKS This command should be used instead of the usual |mode_setup|
+ command. The forms |EPS_mode_setup| and |EPS_mode_setup 1|
+ are equivalent. One of them (preferably the former one) should
+ be used for normal processing. Invoking |EPS_mode_setup 0|
+ is meant primariliy for testing purposes and is supposed
+ to be used by experienced programmers who know what they are doing.
+ There are two predefined constants in MFTOEPS.MF to be used in this
+ context, namely, |no_export_level=0| and |compatibility_level=1|.
+ It is advisable to use the names of the constants rather than
+ bare numbers.
+
+COMMAND write_preamble
+USAGE write_preamble <string>;
+REMARKS This command initialises the process of writing of the PostScript
+ code. The string expression is the name (without extension)
+ of the resulting EPS file; the extension is always |.EPS|.
+ METAFONT is switched to the |batchmode| in order to avoid
+ slowing down the process by writing mess(ages) to the terminal.
+ The inspection of the log file is thus highly recommended.
+
+COMMAND write_postamble
+USAGE write_postamble;
+REMARKS This command ends writing of the PostScript code, switches METAFONT
+ back to the |errorstopmode|, and performs neccessary ``last minute''
+ actions (see below).
+
+COMMANDS set_BB find_BB reset_BB
+USAGE set_BB <four numbers or two pairs separated by commas>;
+ find_BB <a list of paths separated by commas>;
+ reset_BB;
+REMARKS Commands |set_BB| or |find_BB| should be invoked prior to
+ invoking |write_preamble|. |set_BB| sets the coordinates of
+ the corners of the bounding box of a graphic object; it is
+ useful when the bounding box of a graphic object is
+ known in advance or if it is required to force an artificial
+ bounding box. |find_BB| computes the respective bounding box
+ for a list of paths; if several |find_BB| statements are
+ used, the common bounding box is calculated for all paths
+ that appeared in the arguments. The result is stored in the
+ variables |xl_crd|, |yl_crd|, |xh_crd|, and |yh_crd|. There
+ are two functions, |llxy| and |urxy|, returning pairs
+ |(xl_crd,yl_crd)| and |(xh_crd,yh_crd)|, respectively. The
+ last command, |reset_BB|, makes |xl_crd|, |yl_crd|,
+ |xh_crd|, and |yh_crd| undefined (the initial situation);
+ |reset_BB| is performed by the |write_postamble| macro,
+ which is convenient in the case of generating several
+ several EPS files in a single METAFONT run.
+
+COMMANDS fill_C draw_C
+USAGE fill_C <a list of paths separated by commas>;
+ draw_C <a list of paths separated by commas>;
+REMARKS These commands are to be used instead of the usual
+ METAFONT |fill| and |draw| ones. They cause that a list of paths
+ followed by the PostScript operation |eofill| (|fill_C|) or |stroke|
+ (|draw_C|) is translated to a PostScript code. The list of paths
+ constitutes a single curve in the sense of PostScript.
+
+COMMAND clip_C
+USAGE clip_C <a list of paths separated by commas, possibly empty>;
+REMARKS The macro |clip_C| with a non-empty parameter works similarly to
+ the |fill_C| command, except that the |eoclip| operator is issued
+ instead of |eofill|. This causes an appropriate change of
+ the current clipping area. According to PostScript's principles,
+ the resulting area is a set product of the current clipping
+ area and the area specified in the argument of the |eoclip|
+ command. The empty parameter marks the end of the scope
+ of the most recent |clip_C| command with a non-empty parameter.
+ In other words, nested |clip_C| commands form a ``stack'' structure.
+ If needed, the appropriate number of parameterless |clip_C|
+ commands is issued by the |write_postamble| macro, thus
+ the user needs not to care about it.
+ WARNING: files produced with the use of |clip_C| are
+ interpreted properly by Adobe Illustrator (provided paths
+ directions are defined properly) but not by CorelDRAW! (ver. 3.0).
+
+COMMANDS fix_line_width fix_line_join fix_line_cap fix_miter_limit fix_dash
+USAGE fix_line_width <a non-negative number (dimension)>;
+ fix_line_join <a number (0, 1 or 2)>;
+ fix_line_cap <a number (0, 1 or 2)>;
+ fix_miter_limit <a number greater or equal 1>;
+ fix_dash (<a list of numbers (dimensions), possibly empty>)
+ <number (dimension)>;
+REMARKS These command are to be used in connection with the |draw_C|
+ command. |fix_line_width| fixes the thickness of the outline.
+ The other three commands correspond to PostScript operations
+ |setlinejoin|, |setlinecap|, |setmiterlimit|, and |setdash| (see
+ ``PostScript Language Reference Journal'' for details).
+
+ All commands should be used after |write_preamble|, as
+ |write_preamble| sets the default thickness (0.4pt), default
+ line join (0), default line cap (0), default miter limit (10),
+ and a solid line as a default for stroking (|fix_dash () 0|).
+
+COMMANDS fix_fill_cmyk fix_draw_cmyk
+USAGE fix_fill_cmyk <four numbers separated by commas>;
+ fix_draw_cmyk <four numbers separated by commas>;
+REMARKS These commands define the colours of the interiors of graphic
+ objects (|fix_fill_cmyk|) and colours of outlines (|fix_draw_cmyk|)
+ using cyan-magenta-yellow-black model (basic model). They should
+ be used after |write_preamble| (because |write_preamble| defines
+ the black colour as a default for both macros) and prior to invoking
+ the corresponding |fill_C| and |draw_C| commands, respectively.
+ There are also (just in case) macros |fix_fill_rgb| and
+ |fix_draw_rgb| using red-green-blue model; the argument to both
+ macros is a triple of numbers. (The user can control the process
+ of conversion from RGB to CMYK by the redefinition of macros
+ |under_color_removal| and |black_generation|.) The numbers
+ forming the arguments of the macros are supposed to belong to
+ the interval [0..1].
+
+ADDITIONAL FUNCTIONS pos_turn neg_turn
+USAGE pos_turn <primary path expression>
+ neg_turn <primary path expression>
+REMARKS Each function returns the path passed as the argument,
+ except that the orientation of the path is changed, if
+ necessary: |pos_turn| returns paths oriented anti-clockwise,
+ |neg_turn|---oriented clockwise. This may be
+ usefull for creation pictures which are to be processed
+ further by Adobe Illustrator, because this program is
+ sensitive to the orientation of paths.
+
+CONTROL VARIABLES yeseps yesEPS YESEPS
+REMARKS No EPS file will be generated unless one variable among
+ |yeseps| or |yesEPS| or |YESEPS| is assigned a definite value.
+ It is advisable to set this variable in a command line
+ (see M2E.BAT and M2E-ALT.BAT in the PROGS directory).
+ In fact, using |yeseps| is reccomended. Aliases |yesEPS|
+ and |YESEPS| were introduced for ``historical'' reasons.
+
+CONTROL VARIABLE testing
+REMARKS If the variable |testing| is assigned a definite value, the whole
+ PostScript code is flushed to the terminal, thus slowing
+ down significantly the process of generation of an EPS file
+ (cf. the description of the |write_preamble| command).
+
+-----------------------------------------------------------------------------
+
+ENCOURAGEMENT
+
+The inspection of the source code of the MFTOEPS.MF program may reveal
+a few more useful macros.
+
+-----------------------------------------------------------------------------
+
+END OF THE 0MFTOEPS.DOC FILE
diff --git a/graphics/MF-PS/mftoeps/README b/graphics/MF-PS/mftoeps/README
new file mode 120000
index 0000000000..42494cf21b
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/README
@@ -0,0 +1 @@
+0mftoeps.doc \ No newline at end of file
diff --git a/graphics/MF-PS/mftoeps/m2esamp/0m2esamp.doc b/graphics/MF-PS/mftoeps/m2esamp/0m2esamp.doc
new file mode 100644
index 0000000000..fd27e761c4
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/0m2esamp.doc
@@ -0,0 +1,35 @@
+This file belongs to the MFTOEPS package.
+
+The directory M2ESAMP contains the following files:
+ 0M2ESAMP.DOC this file
+ CLIPCIR.MF a bogus application of clipping: a variation of CLIPSQR.MF
+ CLIPSQR.MF a bogus application of clipping: Sierpi\'nski's carpet
+ HOLECLIP.MF a nearly trivial example
+ HOLECLIP.TEX an example of using HOLECLIP.EPS
+ HOLEFILL.MF a nearly trivial example
+ POLYGONS.MF input for SAMPLE*.MF files
+ RECTAN.MF a truly trivial example
+ RECTAN_.BAT DOS batch file for RECTAN.MF (generates RECTAN.EPS)
+ SAMPLE1A.MF less trivial example
+ SAMPLE1B.MF modification of SAMPLE1A.MF
+ SAMPLE2A.MF regular polygon with circumscribed ``flex'' polygon
+ SAMPLE2B.MF ditto---a variation
+ SAMPLE2C.MF ditto---a variation
+ SAMPLE2D.MF ditto---a variation
+ SAMPLE2E.MF ditto---a variation
+ SAMPLE3.MF four pictures (``flowers'')
+ SAMPLE4.MF four pictures (``galaxies'')
+ SAMPLE5.MF four pictures (``shells'')
+ STEREO.MF two pictures that can be used for
+ constructing a simple stereogram
+
+You are entitled to do with these files whatever you wish. If you alter
+a file, however, please remove the comment line:
+
+ `This file belongs to the MFTOEPS package.'
+
+in order to avoid mess.
+
+-----------------------------------------------------------------------------
+
+END OF THE 0M2ESAMP.DOC FILE
diff --git a/graphics/MF-PS/mftoeps/m2esamp/README b/graphics/MF-PS/mftoeps/m2esamp/README
new file mode 120000
index 0000000000..f0f79bedea
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/README
@@ -0,0 +1 @@
+0m2esamp.doc \ No newline at end of file
diff --git a/graphics/MF-PS/mftoeps/m2esamp/clipcir.mf b/graphics/MF-PS/mftoeps/m2esamp/clipcir.mf
new file mode 100644
index 0000000000..50cf091764
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/clipcir.mf
@@ -0,0 +1,39 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% CLIPCIR.MF
+% ---
+input mftoeps; eps_mode_setup;
+% ---
+def ^ = ** enddef; % syntactic sugar
+primarydef i // n = % ditto
+ (if n=0: 0 else: i/n fi)
+% why not to divide by 0?
+enddef;
+def shifted_accordingly(expr i,j,n,D)=
+ shifted ((i//n)[1/2D,w-1/2D],(j//n)[1/2D,w-1/2D])
+enddef;
+% ---
+w#=16mm#; h#=16mm#; define_pixels(w,h);
+for N:=1,2,3,4: % 5, 6, ..., infinity
+ set_BB 0,0,w,h;
+ write_preamble jobname & decimal(N);
+ D:=2w;
+ for n:=0 for q:=1 upto N-1: , 2^q-1 endfor:
+% i.e., |for n:=0, 2^1-1, 2^2-1, ..., 2^(N-1)-1:|
+ path p[], q[]; D:=1/2D; k:=-1;
+ for i:=0 upto n: for j:=0 upto n:
+ k:=k+1;
+ p[k]=fullcircle scaled D
+ shifted_accordingly(i,j,n,D);
+ q[k]=reverse fullcircle scaled 1/3D
+ shifted_accordingly(i,j,n,D);
+ endfor; endfor;
+ clip_C p0, q0 for i:=1 upto k: , p[i], q[i] endfor;
+ endfor;
+ fill_C unitsquare scaled w;
+ write_postamble;
+endfor;
+% ---
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/clipsqu.mf b/graphics/MF-PS/mftoeps/m2esamp/clipsqu.mf
new file mode 100644
index 0000000000..266ec217ae
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/clipsqu.mf
@@ -0,0 +1,39 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% CLIPSQU.MF (Sierpi\'nski's carpet)
+% ---
+input mftoeps; eps_mode_setup;
+% ---
+def ^ = ** enddef; % syntactic sugar
+primarydef i // n = % ditto
+ (if n=0: 0 else: i/n fi)
+% why not to divide by 0?
+enddef;
+def shifted_accordingly(expr i,j,n,D)=
+ shifted ((i//n)[0,w-D],(j//n)[0,w-D])
+enddef;
+% ---
+w#=16mm#; h#=16mm#; define_pixels(w,h);
+for N:=1,2,3: % 4, 5, 6, ..., infinity
+ set_BB 0,0,w,h;
+ write_preamble jobname & decimal(N);
+ D:=3w;
+ for n:=0 for q:=1 upto N-1: , 3^q-1 endfor:
+% i.e., |for n:=0, 3^1-1, 3^2-1, ..., 3^(N-1)-1:|
+ path p[], q[]; D:=1/3D; k:=-1;
+ for i:=0 upto n: for j:=0 upto n:
+ k:=k+1;
+ p[k]=unitsquare scaled D
+ shifted_accordingly(i,j,n,D);
+ q[k]=reverse unitsquare scaled 1/3D
+ shifted (1/3D,1/3D) shifted_accordingly(i,j,n,D);
+ endfor; endfor;
+ clip_C p0, q0 for i:=1 upto k: , p[i], q[i] endfor;
+ endfor;
+ fill_C unitsquare scaled w;
+ write_postamble;
+endfor;
+% ---
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/holeclip.mf b/graphics/MF-PS/mftoeps/m2esamp/holeclip.mf
new file mode 100644
index 0000000000..0b5850a889
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/holeclip.mf
@@ -0,0 +1,20 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% HOLECLIP.MF---a nearly trivial example
+% ---
+input mftoeps; eps_mode_setup;
+w#=4cm#; h#=2cm#; define_pixels(w,h);
+set_BB origin, (w,h);
+write_preamble jobname;
+ fix_fill_cmyk 0,0,0,.25; % 25 percent of black
+ for oper:="draw_C", "clip_C":
+ scantokens oper
+% outer edge:
+ fullcircle xscaled w yscaled h shifted (.5w,.5h),
+% inner edge:
+ reverse fullcircle xscaled .7w yscaled .7h shifted (.5w,.5h);
+ endfor
+write_postamble;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/holeclip.tex b/graphics/MF-PS/mftoeps/m2esamp/holeclip.tex
new file mode 100644
index 0000000000..8f314a6ba8
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/holeclip.tex
@@ -0,0 +1,22 @@
+\input epsf
+
+\centerline{
+\setbox0\vbox{
+ \hbox{It is a clipped text.}\hbox{It is a clipped text.}
+ \hbox{It is a clipped text.}\hbox{It is a clipped text.}
+ \vss % no depth
+}%
+\special{ps:
+ /mftoeps_save save def % the snapshoot of a current stage
+ /mftoeps_bhook {/q {} def /Q {} def} def
+ /CM matrix currentmatrix def
+ currentpoint /cy exch def /cx exch def
+ /ori@endspecial /@endspecial load def
+ /@endspecial {} def % neutralize /@endspecial locally
+}
+\hbox to\wd0{\hss\epsfysize\ht0\epsffile{holeclip.eps}\hss}% perform clipping
+\special{ps:cx cy moveto CM setmatrix}\llap{\copy0}% set the text
+\special{ps:ori@endspecial mftoeps_save restore}% restore a previous stage
+}
+
+\end
diff --git a/graphics/MF-PS/mftoeps/m2esamp/holefill.mf b/graphics/MF-PS/mftoeps/m2esamp/holefill.mf
new file mode 100644
index 0000000000..7478df585d
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/holefill.mf
@@ -0,0 +1,21 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% HOLEFILL.MF---a nearly trivial example
+% ---
+input mftoeps; eps_mode_setup;
+w#=4cm#; h#=2cm#; define_pixels(w,h);
+set_BB origin, (w,h);
+write_preamble jobname;
+ fix_fill_cmyk 0,0,0,.25; % 25 percent of black
+ fix_line_width 1pt;
+ for oper:="draw_C", "fill_C":
+ scantokens oper
+% outer edge:
+ fullcircle xscaled w yscaled h shifted (.5w,.5h),
+% inner edge:
+ reverse fullcircle xscaled .7w yscaled .7h shifted (.5w,.5h);
+ endfor
+write_postamble;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/polygons.mf b/graphics/MF-PS/mftoeps/m2esamp/polygons.mf
new file mode 100644
index 0000000000..29d370d8ee
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/polygons.mf
@@ -0,0 +1,32 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% POLYGONS.MF
+% ---
+vardef regular_polygon(expr n) =
+% |n| is the number of vertices; the diameter of the circumscribed circle
+% is equal to 1, its center is in the origin
+ (up % first vertex
+ for i:=1 upto n-1:
+ -- (up rotated (i*(360/n))) % next vertices
+ endfor
+ -- cycle) scaled .5
+enddef;
+vardef flex_polygon(expr n,a,b) =
+% |n| is the number of vertices, |a|, |b| are the angles (at vertices)
+% between a tangent to a ``flex side'' and the corresponding secant
+ save zz; pair zz[ ]; % array of vertices
+ for i:=0 upto n-1:
+ zz[i]:=up rotated (i*(360/n));
+ endfor
+ (zz[0] {(zz[1]-zz[0]) rotated a}
+ for i:=1 upto n-1:
+ .. {(zz[i]-zz[i-1]) rotated b}
+ zz[i]
+ {(zz[(i+1) mod n]-zz[i]) rotated a}
+ endfor
+ .. {(zz[0]-zz[n-1]) rotated b} cycle)
+ scaled .5
+enddef;
+endinput
diff --git a/graphics/MF-PS/mftoeps/m2esamp/rectan.mf b/graphics/MF-PS/mftoeps/m2esamp/rectan.mf
new file mode 100644
index 0000000000..63802ab54d
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/rectan.mf
@@ -0,0 +1,19 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% RECTAN.MF---a trivial example
+% ---
+input mftoeps;
+EPS_mode_setup;
+beginchar(48, % ASCII code (unimportant)
+ 2cm#, % width
+ 1cm#, % height
+ 0cm# % depth
+ );
+ set_BB 0,-d,w,h; % coordinates of the corners of the bounding box
+ write_preamble "rectan";
+ fill_C unitsquare xscaled w yscaled h;
+ write_postamble;
+endchar;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/rectan_.bat b/graphics/MF-PS/mftoeps/m2esamp/rectan_.bat
new file mode 100644
index 0000000000..596fd4710a
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/rectan_.bat
@@ -0,0 +1,4 @@
+::
+:: This file belongs to the MFTOEPS package.
+::
+call m2e rectan
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample1a.mf b/graphics/MF-PS/mftoeps/m2esamp/sample1a.mf
new file mode 100644
index 0000000000..cd34bd3307
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample1a.mf
@@ -0,0 +1,24 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE1A.MF
+% ---
+input polygons; % the definition of the |regular_polygon| function
+input mftoeps;
+eps_mode_setup;
+beginchar(0,2cm#,2cm#,0);
+ path P[ ]; % ,,room'' for polygons
+ N:=25; % the number of polygons
+% preparing:
+ for i:=1 upto N:
+ P[i]:=regular_polygon(7)
+ scaled ((i/N)**2*w) rotated (i/N*360) shifted (.5w,.5h);
+ endfor;
+% exporting:
+ find_BB for i:=1 upto N-1: P[i], endfor P[N];
+ write_preamble jobname;
+ draw_C for i:=1 upto N-1: P[i], endfor P[N];
+ write_postamble;
+endchar;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample1b.mf b/graphics/MF-PS/mftoeps/m2esamp/sample1b.mf
new file mode 100644
index 0000000000..499650af1f
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample1b.mf
@@ -0,0 +1,28 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE1B.MF
+% ---
+input polygons; % the definition of the |regular_polygon| function
+input mftoeps;
+eps_mode_setup;
+beginchar(0,2cm#,2cm#,0);
+ path P[ ]; % ,,room'' for polygons
+ N:=25; % the number of polygons
+% preparing:
+ for i:=1 upto N:
+ P[i]:=regular_polygon(7)
+ scaled ((i/N)**2*w) rotated (i/N*360) shifted (.5w,.5h);
+ endfor;
+% exporting:
+ find_BB for i:=1 upto N-1: P[i], endfor P[N];
+ write_preamble jobname;
+% Adobe Illustrator likes to control the orientation of paths
+ fill_C
+ for i:=1 upto N-1:
+ if odd(N-i+1): pos_turn else: neg_turn fi P[i],
+ endfor pos_turn P[N];
+ write_postamble;
+endchar;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample2a.mf b/graphics/MF-PS/mftoeps/m2esamp/sample2a.mf
new file mode 100644
index 0000000000..ef34b34ea8
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample2a.mf
@@ -0,0 +1,23 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE2A.MF
+% ---
+input polygons;
+input mftoeps;
+eps_mode_setup;
+beginchar(0,16mm#,16mm#,0);
+ path P[ ]; % ``room'' for two polygons
+% preparing:
+ P[1]:=regular_polygon(7) scaled w shifted (.5w,.5h);
+ P[2]:=flex_polygon(7,0,0) scaled w shifted (.5w,.5h);
+% exporting:
+ find_BB P[1], P[2];
+ write_preamble jobname;
+ fix_fill_cmyk 0,0,0,.25; % 25 percent of black
+ fix_line_width 1pt;
+ fill_C P1; draw_C P2;
+ write_postamble;
+endchar;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample2b.mf b/graphics/MF-PS/mftoeps/m2esamp/sample2b.mf
new file mode 100644
index 0000000000..e6d82b3175
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample2b.mf
@@ -0,0 +1,23 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE2B.MF
+% ---
+input polygons;
+input mftoeps;
+eps_mode_setup;
+beginchar(0,16mm#,16mm#,0);
+ path P[ ]; % ``room'' for two polygons
+% preparing:
+ P[1]:=regular_polygon(7) scaled w shifted (.5w,.5h);
+ P[2]:=flex_polygon(7,-180/7,180/7) scaled w shifted (.5w,.5h);
+% exporting:
+ find_BB P[1], P[2];
+ write_preamble jobname;
+ fix_fill_cmyk 0,0,0,.25; % 25 percent of black
+ fix_line_width 1pt;
+ fill_C P1; draw_C P2;
+ write_postamble;
+endchar;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample2c.mf b/graphics/MF-PS/mftoeps/m2esamp/sample2c.mf
new file mode 100644
index 0000000000..2a2ebffb4f
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample2c.mf
@@ -0,0 +1,23 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE2C.MF
+% ---
+input polygons;
+input mftoeps;
+eps_mode_setup;
+beginchar(0,16mm#,16mm#,0);
+ path P[ ]; % ``room'' for two polygons
+% preparing:
+ P[1]:=regular_polygon(7) scaled w shifted (.5w,.5h);
+ P[2]:=flex_polygon(7,45,45) scaled w shifted (.5w,.5h);
+% exporting:
+ find_BB P[1], P[2];
+ write_preamble jobname;
+ fix_fill_cmyk 0,0,0,.25; % 25 percent of black
+ fix_line_width 1pt;
+ fill_C P1; draw_C P2;
+ write_postamble;
+endchar;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample2d.mf b/graphics/MF-PS/mftoeps/m2esamp/sample2d.mf
new file mode 100644
index 0000000000..8fe9f9bfb5
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample2d.mf
@@ -0,0 +1,23 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE2D.MF
+% ---
+input polygons;
+input mftoeps;
+eps_mode_setup;
+beginchar(0,16mm#,16mm#,0);
+ path P[ ]; % ``room'' for two polygons
+% preparing:
+ P[1]:=regular_polygon(7) scaled w shifted (.5w,.5h);
+ P[2]:=flex_polygon(7,-45,45) scaled w shifted (.5w,.5h);
+% exporting:
+ find_BB P[1], P[2];
+ write_preamble jobname;
+ fix_fill_cmyk 0,0,0,.25; % 25 percent of black
+ fix_line_width 1pt;
+ fill_C P1; draw_C P2;
+ write_postamble;
+endchar;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample2e.mf b/graphics/MF-PS/mftoeps/m2esamp/sample2e.mf
new file mode 100644
index 0000000000..9411c1db40
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample2e.mf
@@ -0,0 +1,23 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE2E.MF
+% ---
+input polygons;
+input mftoeps;
+eps_mode_setup;
+beginchar(0,16mm#,16mm#,0);
+ path P[ ]; % ``room'' for two polygons
+% preparing:
+ P[1]:=regular_polygon(7) scaled w shifted (.5w,.5h);
+ P[2]:=flex_polygon(7,45,-45) scaled w shifted (.5w,.5h);
+% exporting:
+ find_BB P[1], P[2];
+ write_preamble jobname;
+ fix_fill_cmyk 0,0,0,.25; % 25 percent of black
+ fix_line_width 1pt;
+ fill_C P1; draw_C P2;
+ write_postamble;
+endchar;
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample3.mf b/graphics/MF-PS/mftoeps/m2esamp/sample3.mf
new file mode 100644
index 0000000000..c58756e37a
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample3.mf
@@ -0,0 +1,53 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE3.MF
+% ---
+input mftoeps;
+input polygons;
+eps_mode_setup;
+% unpercent the following line if the coloured version is needed
+% coloured:=1;
+% ---
+def write_paths(expr name) =
+ find_BB elem_path1;
+ write_preamble name;
+ for i:=1 upto objects:
+ coeff:=
+ if objects=1: 0 else: .5(1-cosd(((i-1)/(objects-1))[alpha1,alpha2])) fi;
+ fix_fill_cmyk forsuffixes $:=cyan, magenta, yellow: coeff[$1,$2], endfor
+ coeff[black1,black2];
+ fill_C elem_path[i];
+ endfor;
+ write_postamble;
+enddef;
+% ---
+ch_max:=3;
+% ---
+for ch:=0 upto ch_max:
+ beginchar(char(ASCII("a")+ch), 1in#, 1in#, 0);
+ path elem_path[\\];
+ objects:=100; transitions:=3;
+ sca1:=w; sca2:=.02w;
+ rot1:=0; rot2:=(ch/ch_max)[25,180];
+ skew1:=45; skew2:=0;
+ alpha1:=0; alpha2:=transitions*360;
+ if known coloured:
+ cyan1:=0; magenta1:=0; yellow1:=1; black1:=0;
+ cyan2:=0.35294; magenta2:=0.8353; yellow2:=0.8353; black2:=0; % brown
+ else:
+ cyan1:=0; magenta1:=0; yellow1:=0; black1:=0.7;
+ cyan2:=0; magenta2:=0; yellow2:=0; black2:=0.15;
+ fi
+ for i:=1 upto objects:
+ coeff:=if objects=1: 0 else: (i-1)/(objects-1) fi;
+ elem_path[i]:=flex_polygon(5,coeff[skew1,skew2],coeff[skew1,skew2])
+ scaled (coeff[sca1,sca2])
+ rotated (coeff[rot1,rot2]) shifted (.5w,.5h);
+ endfor
+ write_paths(jobname & char(ASCII("a")+ch));
+ endchar;
+endfor
+% ---
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample4.mf b/graphics/MF-PS/mftoeps/m2esamp/sample4.mf
new file mode 100644
index 0000000000..37acefb4d0
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample4.mf
@@ -0,0 +1,45 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE4.MF
+% ---
+input mftoeps;
+input polygons;
+eps_mode_setup;
+% ---
+def write_paths(expr name) =
+ find_BB elem_path1;
+ write_preamble name;
+ for i:=1 upto objects:
+ coeff:=
+ if objects=1: 0 else: .5(1-cosd(((i-1)/(objects-1))[alpha1,alpha2])) fi;
+ fix_fill_cmyk forsuffixes $:=cyan, magenta, yellow: coeff[$1,$2], endfor
+ coeff[black1,black2];
+ fill_C elem_path[i];
+ endfor;
+ write_postamble;
+enddef;
+% ---
+ch_max:=3;
+% ---
+for ch:=0 upto ch_max:
+ beginchar(char(ASCII("a")+ch), 1in#, 1in#, 0);
+ path elem_path[\\];
+ objects:=100; transitions:=.5; % regular 2
+ sca1:=w; sca2:=.05w;
+ rot1:=0; rot2:=(ch/ch_max)[0,-360];
+ alpha1:=0; alpha2:=transitions*360;
+ cyan1:=0; magenta1:=0; yellow1:=0; black1:=0.05;
+ cyan2:=0; magenta2:=0; yellow2:=0; black2:=0.9;
+ for i:=1 upto objects:
+ coeff:=if objects=1: 0 else: (i-1)/(objects-1) fi;
+ elem_path[i]:= flex_polygon(6,(coeff**.1)[-30,0],(coeff**.1)[30,0])
+ scaled (coeff[sca1,sca2])
+ rotated (coeff[rot1,rot2]+30) shifted (.5w,.5h);
+ endfor
+ write_paths(jobname & char(ASCII("a")+ch));
+ endchar;
+endfor
+% ---
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/sample5.mf b/graphics/MF-PS/mftoeps/m2esamp/sample5.mf
new file mode 100644
index 0000000000..c7e0c7742b
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/sample5.mf
@@ -0,0 +1,38 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% SAMPLE5.MF
+% ---
+input mftoeps;
+input polygons;
+eps_mode_setup;
+% ---
+def soft_polygon (expr n,a) = flex_polygon(n,a-180/n,a+180/n) enddef;
+% ---
+def write_paths(expr name) =
+ find_BB for i:=1 upto objects: elem_path[i], endfor elem_path[objects];
+ write_preamble name;
+ fix_line_width .2pt; for i:=1 upto objects: draw_C elem_path[i]; endfor;
+ write_postamble;
+enddef;
+% ---
+ch_max:=3;
+% ---
+for ch:=0 upto ch_max:
+ beginchar(char(ASCII("a")+ch), 1in#, 1in#, 0);
+ path elem_path[\\];
+ objects:=17;
+ sca1:=.85w; sca2:=.02w;
+ rot1:=0; rot2:=(ch/ch_max)[5,120];
+ skew1:=(ch/ch_max)[60,30]; skew2:=0;
+ for i:=1 upto objects:
+ coeff:=if objects=1: 0 else: (i-1)/(objects-1) fi;
+ elem_path[i]:= soft_polygon(7,coeff[skew1,skew2])
+ scaled (coeff[sca1,sca2]) rotated (coeff[rot1,rot2]+30) shifted (.5w,.5h);
+ endfor
+ write_paths(jobname & char(ASCII("a")+ch));
+ endchar;
+endfor
+% ---
+end.
diff --git a/graphics/MF-PS/mftoeps/m2esamp/stereo.mf b/graphics/MF-PS/mftoeps/m2esamp/stereo.mf
new file mode 100644
index 0000000000..c3e85ec53f
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/m2esamp/stereo.mf
@@ -0,0 +1,53 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+% ---
+% STEREO.MF
+% ---
+input mftoeps;
+input polygons;
+eps_mode_setup;
+% ---
+def soft_polygon (expr n,a) = flex_polygon(n,a-180/n,a+180/n) enddef;
+% ---
+def write_paths(expr name) =
+ find_BB for i:=1 upto objects: elem_path[i], endfor elem_path[objects];
+ write_preamble name;
+ for i:=1 upto objects:
+ coeff:=
+ if objects=1: 0 else: .5(1-cosd(((i-1)/(objects-1))[alpha1,alpha2])) fi;
+ coeff:=if coeff>.5: 1 else: 0 fi;
+ fix_fill_cmyk forsuffixes $:=cyan, magenta, yellow: coeff[$1,$2], endfor
+ coeff[black1,black2];
+ fill_C elem_path[i];
+ endfor;
+ write_postamble;
+enddef;
+% ---
+for ch:=0,1:
+ beginchar("0",117pt#, 117pt#, 0);
+ path elem_path[\\];
+ objects:=100; transitions:=7;
+ pair cent[\\];
+ sca1:=.5w; sca2:=.01w;
+ skew1:=60; skew2:=0;
+ alpha1:=0; alpha2:=transitions*360;
+ cshift0:=-.02w; cshift1:=-cshift0;
+ cent1:=(.5w,.5h);
+ rot1:=0; rot2:=rot1+60;
+ cent2:=(.5w+cshift[ch],.49h);
+ cyan1:=0; magenta1:=0; yellow1:=0; black1:=1;
+ cyan2:=0; magenta2:=0; yellow2:=0; black2:=0;
+ for i:=1 upto objects:
+ if objects=1: coeff:=0; else: coeff:=(i-1)/(objects-1); fi
+ elem_path[i]:= soft_polygon(4,coeff[skew1,skew2])
+ scaled (coeff[sca1,sca2])
+ rotated (coeff[rot1,rot2]+30)
+ shifted (coeff[cent1,cent2]);
+ endfor
+ write_paths(jobname & decimal(ch));
+endchar;
+
+endfor
+
+end.
diff --git a/graphics/MF-PS/mftoeps/mftoeps.mf b/graphics/MF-PS/mftoeps/mftoeps.mf
new file mode 100644
index 0000000000..46bc5a1cb9
--- /dev/null
+++ b/graphics/MF-PS/mftoeps/mftoeps.mf
@@ -0,0 +1,748 @@
+%%%%
+%%%% This file belongs to the MFTOEPS package.
+%%%%
+%%% mod div
+%%% length cycle pos_turn neg_turn
+%%% endchar ori_endchar
+%%% draw eofill killtext
+%%% draw find_BB set_BB reset_BB
+%%% draw draw_C normal_draw_C no_export_draw_C
+%%% draw fill_C normal_fill_C no_export_fill_C
+%%% draw clip_C normal_clip_C
+%%% draw write_preamble normal_write_preamble no_export_write_preamble
+%%% endchar write_postamble normal_write_postamble no_export_write_postamble
+%%% endchar g_save g_restore
+%%% message write_PS normal_write_PS
+%%% draw write_def
+%%% draw fix_line_width set_line_width
+%%% draw fix_line_join set_line_join fix_line_cap set_line_cap
+%%% draw fix_miter_limit set_miter_limit fix_dash set_dash
+%%% draw fix_fill_cmyk set_fill_cmyk fix_draw_cmyk set_draw_cmyk
+%%% draw fix_fill_rgb set_fill_rgb fix_draw_rgb set_draw_rgb
+%%% xpart norm_color
+%%% mode_setup ori_mode_setup eps_mode_setup EPS_mode_setup
+%%% draw mftoeps_default
+%%\vsize245mm
+%%\font\titfnt cmtt10 at 48 pt
+%%{\let\makefootline\empty \let\makeheadline\empty
+%%\vglue0ptplus1fill
+%%\centerline{\titfnt MFTOEPS.MF}
+%%\bigskip
+%%\centerline{ver. 0.68 (Tuesday, March 4th, 1997)}
+%%\vfill\vfill\eject}
+% ---
+% \MF format for exporting to EPS via LOG-file + AWK-like utility
+% ---
+% NAME: MFTOEPS.MF
+% AUTHORS: B. Jackowski, P. Pianowski, M. Ry\'cko
+% HISTORY:
+% Version 0.5 (Friday, May 5th, 1995): first public domain release
+% Version 0.6 (Thursday, July 27th, 1995): major revision
+% * macro |reset_BB| added (it was silly not to have it)
+% * |pickup pencircle scaled 0.4pt| performed by |no_export_write_preamble|
+% * `mftoeps_bhook' and `mftoeps_ehook' introduced
+% * `setlinecap', `setlinejoin', `setmiterlimit', and `setdash' included
+% * switching between no export and compatibility modes made more tidy
+% * colours are forced to fall into the interval [0..1]
+% * formatting, comments and internal naming altered
+% Version 0.65 (Friday, September 1st, 1995):
+% A lot of small changes introduced introduced during the work over
+% PSTOEPS and EPSTOMF converters, and over ROEX macros:
+% * defaults for line joins and caps changed (WARNING: incompatibility
+% with the version 0.6 described in proceedings of 9th European \TeX
+% Conference, Arnhem, Holland); now they are compatible with PostScript,
+% not with our predilections
+% * `gsave'/`grestore' grouping added (macros |g_save| and |g_restore|);
+% the graphic object is embedded into a `gsave'/`grestore' pair
+% * |set_BB| and |find_BB| available also in no-export mode
+% * string variable |extra_eps_setup| added
+% * a general purpose macro |make_list| added
+% * version number appears in the header of EPS file
+% * |reset_BB| performed by newly introduced |no_export_write_postamble|
+% * definitions of EPS header more robust
+% * macros |pos_turn|, |neg_turn|, and |is_line| more robust
+% * global defaults defined as in ROEX (macro |mftoeps_default|)
+% * code optimized, formatting slightly altered (e.g., the underscore
+% character ending a name appears as a superscript asterisk)
+% This version was released during the 9th EuroTeX meeting in Arnhem
+% Version 0.66 (Tuesday, September 19th, 1995):
+% * |find_BB| a bit more robust
+% * |is_line| is exactly the same as in ROEX.MF (it should have been
+% in version 0.65...)
+% This version was released during the CyrTUG-95 meeting in Moscow
+% Version 0.67 (Friday, October 27th, 1995):
+% * |miter_limit| used to be a dimen; it was my mistake (BJ),
+% in PostScript it is a dimensionless quantity
+% Version 0.68 (Tuesday, March 4th, 1997):
+% * |extra_preamble| and |extra_postamble| added
+% ---
+if known mftoeps: expandafter endinput fi % no double loading
+mftoeps:=1;
+vardef mftoeps_ver ="0.68" enddef;
+% ---
+% DECLARATIONS (only explicitly needed):
+no_export_level=0; compatibility_level=1; % constants
+let ori_mode_setup=mode_setup;
+let ori_endchar=endchar;
+boolean closed_path; % set by |normal_fill_C|, |normal_draw_C|,
+ % |close_op|, and just before writing definitions
+ % of |mid_draw_op|; checked by |mid_draw_op|;
+boolean dash_array_empty; % used locally by |set_dash|
+boolean known_yes_eps; % used by |eps_mode_setup|
+string extra_eps_setup; % used by |eps_mode| for last-minute adjustments
+extra_eps_setup=""; % usually there's nothing special to do
+string extra_preamble, extra_postamble; % for special comments and/or defs
+extra_preamble=extra_postamble=""; % usually there's nothing special to add
+% We follow the naming convention of The \MF{}book:
+% ``Private tokens always end with the underscore character.''
+% Since the underscore is a rather illegible character, in a ``neat''
+% printing (using MFT utility) it will appear as an superscript asterisk.
+%% % an innocent formatting trick: the underscore character ending a name
+%% % will be typeset as an superscript asterisk
+%% \let\oriunderscore\_
+%% \newif\ifbgroupopen \bgroupopenfalse
+%% \def\altdblbackslash#1{\bgroup\bgroupopentrue\it#1}
+%% \def\optegroup{\ifbgroupopen\egroup\fi}
+%% \def\underscoreasasterisk#1{%
+%% \ifx#1\relax\optegroup^*\else\oriunderscore#1\fi}
+%% \def\\#1{%
+%% \let\_\underscoreasasterisk
+%% \altdblbackslash{#1\relax}\optegroup
+%% \let\_\oriunderscore}
+% ---
+def make_list(expr k,l) suffix s =
+ for i_:=k upto l: if i_>k: , fi \\ s[i_] endfor
+enddef;
+% ---
+vardef distance(expr za,zb) = length(za-zb) enddef; % in fact, an alias
+% ---
+vardef pos_turn primary p =
+ interim autorounding:=0;
+ if check_turn(p)=0: show p;
+ errhelp "I will leave the path intact, continue with crossed fingers.";
+ errmessage "Cannot make positive turn (check_turn=0)";
+ elseif check_turn(p)<0: reverse fi \\ p
+enddef;
+% ---
+vardef neg_turn primary p =
+ interim autorounding:=0;
+ if check_turn(p)=0: show p;
+ errhelp "I will leave the path intact, continue with crossed fingers.";
+ errmessage "Cannot make negative turn (check_turn=0)";
+ elseif check_turn(p)>0: reverse fi \\ p
+enddef;
+% ---
+vardef check_turn primary p = % seems more adequate than |turningnumber|
+% |epsilon|=|totalweight currentpicture| after |fill unitsquare|,
+% |eps/epsilon=32|, i.e., we admit accuracy of 32 pixels (isn't it too many?)
+ save r_,currentpicture; picture currentpicture;
+ interim turningcheck:=0; interim autorounding:=0;
+ currentpicture:=nullpicture; fill p; r_:=totalweight(currentpicture);
+ if r_>eps: 1 elseif r_<-eps: -1 else: turningnumber(p) fi
+enddef;
+% ---
+vardef is_line(expr B) =
+% checks if a B\'ezier segment |B| is an almost straight line;
+% recall that |z reflectedabout (origin,right)=1/z| for a complex
+% number |z| such that |length(z)=1|; recall also that the multiplication
+% of complex numbers (|zscale| operation) implies the addition of
+% their angle arguments
+ save pa_,pb_,pc_,pd_,ba_,da_,dc_; pair pa_,pb_,pc_,pd_,ba_,da_,dc_;
+ pa_:=point 0 of B; pd_:=point 1 of B;
+ if distance(pa_,pd_)<epsil.dist:
+ false % either really not a line or an uncertain situation (rounding errors)
+ else:
+ da_=unitvector(pd_-pa_) reflectedabout (origin,right);
+ pb_:=postcontrol 0 of B; if distance(pa_,pb_)<epsil.dist: pb_:=pa_; fi
+ pc_:=precontrol 1 of B; if distance(pd_,pc_)<epsil.dist: pc_:=pd_; fi
+ if (pa_=pb_) and (pc_=pd_): true
+ elseif (pa_=pb_):
+ dc_=unitvector(pd_-pc_); abs(angle(dc_ zscaled da_))<epsil.ang
+ elseif (pc_=pd_):
+ ba_=unitvector(pb_-pa_); abs(angle(ba_ zscaled da_))<epsil.ang
+ else:
+ ba_=unitvector(pb_-pa_); dc_=unitvector(pd_-pc_);
+ (abs(angle(ba_ zscaled da_))<epsil.ang)
+ and (abs(angle(dc_ zscaled da_))<epsil.ang)
+ fi
+ fi
+enddef;
+% ---
+def eofill expr P =
+ begingroup save pp_; picture pp_;
+ interim turningcheck:=0;
+% the following |addto|s are supposed to fill disjoint areas:
+ pp_:=nullpicture; addto pp_ contour P.t_;
+ cull pp_ keeping (1,infinity); addto currentpicture also pp_;
+ pp_:=nullpicture; addto pp_ contour reverse P.t_;
+ cull pp_ keeping (1,infinity); addto currentpicture also pp_;
+ cull currentpicture keeping(1,1);
+ endgroup
+enddef;
+% ---
+def normal_write_PS expr s = if s<>"": message ":PS: " & s; fi enddef;
+% ---
+def write_P (expr op,P) =
+% writes a point |P| in PostScript, followed by the operation |op|
+ write_PS bp_pair(P) & op;
+enddef;
+% ---
+def write_B (expr op,B) =
+% writes a B\'ezier segment |B| in PostScript, followed by the operation |op|
+ write_PS bp_pair(postcontrol 0 of B) & bp_pair(precontrol 1 of B) &
+ bp_pair(point 1 of B) & op;
+enddef;
+% ---
+def write_L (expr op,L) =
+% writes a line |L| in PostScript, followed by the operation |op|
+ write_PS bp_pair(point 1 of L) & op;
+enddef;
+% ---
+vardef write_C (expr C) =
+% writes a B\'ezier curve |C| in PostScript followed by an operation
+% which depends on whether |C| is cyclic or not
+ save ll_;
+ ll_:= % |(length(C)-ll_,length(C)-ll_+1)| is the last segment processed
+ if (cycle C) and ((point length(C) of C) = (point length(C)-1 of C)):
+ 2 % artificial situation related to an old EPS2MF converter
+ else: 1 fi;
+ write_P(move_op,point 0 of C);
+ for tt_:=0 upto length(C)-ll_:
+ if is_line(subpath (tt_,tt_+1) of C):
+ write_L(line_op,subpath (tt_,tt_+1) of C);
+ else:
+ write_B(bezi_op,subpath (tt_,tt_+1) of C);
+ fi
+ endfor
+ if cycle C: write_PS close_op; fi
+enddef;
+% ---
+def no_export_fill_C text t =
+ begingroup
+ save rr_; picture rr_; % must not be |pp_| (see |eofill|)
+ begingroup
+ save currentpicture; def currentpicture = rr_ enddef; % danger!
+ currentpicture:=nullpicture; for qq_:=t: eofill qq_; endfor
+ endgroup;
+ addto currentpicture also rr_; cullit;
+ endgroup
+enddef;
+% ---
+def normal_fill_C text t =
+ write_PS beg_path_op;
+ set_fill_cmyk;
+ for pp_:=t:
+ write_C(pp_); write_PS mid_fill_op; closed_path:=false;
+ endfor
+ write_PS end_path_op;
+enddef;
+% ---
+def no_export_draw_C text t = for pp_:=t: draw pp_; endfor enddef;
+% ---
+def normal_draw_C text t =
+ write_PS beg_path_op;
+ set_draw_cmyk; set_line_width;
+ set_line_join; set_line_cap;
+ set_miter_limit; set_dash;
+ for pp_:=t:
+ write_C(pp_); write_PS mid_draw_op; closed_path:=false;
+ endfor
+ write_PS end_path_op;
+enddef;
+% ---
+def normal_clip_C text t =
+ clipping_count:=0; % local
+ for pp_:=t: clipping_count:=clipping_count+1; endfor
+ if clipping_count=0:
+ if clipping_level>0: g_restore; clipping_level:=clipping_level-1; fi
+ else:
+ clipping_level:=clipping_level+1; g_save;
+ write_PS beg_path_op;
+ for pp_:=t: write_C(pp_); write_PS mid_clip_op; endfor
+ write_PS end_path_op;
+ fi
+enddef;
+% ---
+vardef update_BC(expr C)(suffix xl,yl,xh,yh) =
+% updates variables |xl|, |yl|, |xh|, |yh| by finding extremal points
+% of a B\'ezier curve |C|
+ if xl>xpart(point 0 of C): xl:=xpart(point 0 of C); fi
+ if xh<xpart(point 0 of C): xh:=xpart(point 0 of C); fi
+ if yl>ypart(point 0 of C): yl:=ypart(point 0 of C); fi
+ if yh<ypart(point 0 of C): yh:=ypart(point 0 of C); fi
+ for tt_:=0 upto length(C)-1:
+ update_BB(subpath (tt_,tt_+1) of C,xl,yl,xh,yh);
+ endfor
+enddef;
+% ---
+vardef update_BB(expr B) (suffix xl,yl,xh,yh) =
+% updates variables |xl|, |yl|, |xh|, |yh| by finding extremal points
+% of a B\'ezier segment |B|; the |point 0 of B| is not taken into account
+ save Bx_,By_,ta_,tb_,vv_; path Bx_, By_; numeric ta_,tb_,vv_;
+%
+ Bx_=(0,xpart(point 0 of B))
+ ..controls
+ (0,xpart(postcontrol 0 of B)) and (1000,xpart(precontrol 1 of B))
+ ..(1000,xpart(point 1 of B));
+ By_=(0,ypart(point 0 of B))
+ ..controls
+ (0,ypart(postcontrol 0 of B)) and (1000,ypart(precontrol 1 of B))
+ ..(1000,ypart(point 1 of B));
+%
+ ta_:=directiontime right of Bx_;
+ if ta_>0:
+ vv_:=ypart (point ta_ of Bx_);
+ if vv_<xl: xl:=vv_; fi\\ if vv_>xh: xh:=vv_; fi
+ tb_:=directiontime right of subpath (ta_+eps,1) of Bx_;
+ if tb_>=0:
+ vv_:=ypart (point tb_ of (subpath (ta_+eps,1) of Bx_));
+ if vv_<xl: xl:=vv_; fi\\ if vv_>xh: xh:=vv_; fi
+ fi
+ fi
+ vv_:=ypart (point 1 of Bx_); if vv_<xl: xl:=vv_; fi\\ if vv_>xh: xh:=vv_; fi
+%
+ ta_:=directiontime right of By_;
+ if ta_>0:
+ vv_:=ypart (point ta_ of By_);
+ if vv_<yl: yl:=vv_; fi\\ if vv_>yh: yh:=vv_; fi
+ tb_:=directiontime right of subpath (ta_+eps,1) of By_;
+ if tb_>=0:
+ vv_:=ypart (point tb_ of (subpath (ta_+eps,1) of By_));
+ if vv_<yl: yl:=vv_; fi\\ if vv_>yh: yh:=vv_; fi
+ fi
+ fi
+ vv_:=ypart (point 1 of By_); if vv_<yl: yl:=vv_; fi\\ if vv_>yh: yh:=vv_; fi
+enddef;
+% ---
+% |xl|, |yl|, |xh|, and |yh| can likely be used in a program, hence
+% longer names: |xl_crd|, |yl_crd|, |xh_crd|, and |yh_crd|, respectively
+def reset_BB =
+ xl_crd:=whatever; yl_crd:=whatever; xh_crd:=whatever; yh_crd:=whatever;
+enddef;
+% ---
+def find_BB text t =
+ for CC_:=t: % |t| may be empty
+ if unknown xl_crd: xl_crd=yl_crd=-xh_crd=-yh_crd=infinity; fi
+ update_BC(CC_)(xl_crd,yl_crd,xh_crd,yh_crd);
+ endfor
+enddef;
+% ---
+vardef llxy = (xl_crd,yl_crd) enddef;
+vardef urxy = (xh_crd,yh_crd) enddef;
+% ---
+def set_BB text t =
+% it may happen that |t| refers to the previously fixed coordinates of the
+% bounding box, therefore the coordinates should not be changed too early
+ numeric xl_crd_, yl_crd_, xh_crd_, yh_crd_;
+ for rr_:=t: % syntax trick
+ if pair rr_:
+ for ss_:=xpart rr_, ypart rr_:
+ if unknown xl_crd_: xl_crd_:=ss_;
+ elseif unknown yl_crd_: yl_crd_:=ss_;
+ elseif unknown xh_crd_: xh_crd_:=ss_;
+ elseif unknown yh_crd_: yh_crd_:=ss_;
+ fi
+ endfor
+ else:
+ if unknown xl_crd_: xl_crd_:=rr_;
+ elseif unknown yl_crd_: yl_crd_:=rr_;
+ elseif unknown xh_crd_: xh_crd_:=rr_;
+ elseif unknown yh_crd_: yh_crd_:=rr_;
+ fi
+ fi
+ endfor
+ numeric xl_crd, yl_crd, xh_crd, yh_crd;
+ xl_crd:=xl_crd_; yl_crd:=yl_crd_; xh_crd:=xh_crd_; yh_crd:=yh_crd_;
+enddef;
+% ---
+% somewhat unusual formula was employed in the definition of |bp_num|
+% because |(72/300)*x| is not equivalent to |72/300x|: the latter yields
+% better accuracy
+vardef bp_num primary x =
+ decimal(scantokens("72/" & decimal(pixels_per_inch))x)
+enddef;
+vardef bp_pair primary z =
+ bp_num(xpart(z)) & " " & bp_num(ypart(z)) & " "
+enddef;
+% ---
+mode_def eps_mode =
+ proofing:=0; % no, we're not making proofs
+ fontmaking:=0; % no, we're not making a TFM file
+ tracingtitles:=1; % yes, show titles online
+ pixels_per_inch:=300; % standard laser printer resolution
+ blacker:=0; % no additional blackness
+ fillin:=0; % no compensation for fillin
+ o_correction:=1; % no reduction in overshoot
+ mag:=1; % standard magnification
+ autorounding:=0; % removing pimples is unimportant
+ scantokens extra_eps_setup; % the user's special last-minute adjustments
+enddef;
+% ---
+mode_def vicar_mode =
+ proofing:=0; % no, we're not making proofs
+ fontmaking:=0; % no, we're not making a TFM file
+ tracingtitles:=1; % yes, show titles online
+ pixels_per_inch:=300; % standard laser printer resolution
+ blacker:=0; % no additional blackness
+ fillin:=0; % no compensation for fillin
+ o_correction:=1; % no reduction in overshoot
+ mag:=1; % standard magnification
+enddef;
+% ---
+def EPS_mode_setup = eps_mode_setup enddef; % an alias (upward compatibility)
+def eps_mode_setup suffix e_l =
+% fixing |export_level|:
+ known_yes_eps:=(known yesEPS) or (known YESEPS) or (known yeseps);
+ if not known_yes_eps: export_level:=no_export_level;
+ elseif str e_l="": export_level:=compatibility_level;
+ else:
+ if
+ (if known e_l:
+ (e_l=no_export_level) or (e_l=compatibility_level)
+ else:
+ false
+ fi):
+ export_level:=e_l;
+ else:
+ message "Default export level assumed.";
+ export_level:=compatibility_level;
+ fi
+ fi
+% |mode_setup| hackery (last chance to abandon exporting):
+ if export_level<>no_export_level:
+ if not (string mode): mode:=vicar_mode; fi % for hackers only
+ mode_setup; % trial setup
+ if proofing>0: export_level:=no_export_level; fi % proofing has priority
+ fi
+% now either |export_level=no_export_level|
+% or |export_level=compatibility_level):
+ if export_level=no_export_level:
+ let mode_setup=ori_mode_setup; mode_setup;
+ let endchar=ori_endchar;
+ let write_PS=killtext;
+ let write_preamble=no_export_write_preamble;
+ let write_postamble=no_export_write_postamble;
+ let fill_C=no_export_fill_C;
+ let draw_C=no_export_draw_C;
+ let clip_C=killtext;
+ else: % |error_level=compatibility_level|
+ if not (string mode): mode:=eps_mode; fi % for hackers only
+ mode_setup; % set private mode
+ let mode_setup=relax; % no more |mode_setup|s
+ def endchar = % no shipping characters out
+ scantokens extra_endchar; endgroup
+ enddef;
+ let write_PS=normal_write_PS;
+ let write_preamble=normal_write_preamble;
+ let write_postamble=normal_write_postamble;
+ let fill_C=normal_fill_C;
+ let draw_C=normal_draw_C;
+ let clip_C=normal_clip_C;
+ fi
+enddef;
+% ---
+def plain_new_path_op = "newpath" enddef;
+def plain_close_op = "closepath" enddef;
+def plain_move_op = "moveto" enddef;
+def plain_line_op = "lineto" enddef;
+def plain_bezi_op = "curveto" enddef;
+def plain_fill_op = "eofill" enddef;
+def plain_draw_op = "stroke" enddef;
+def plain_clip_op = "eoclip" enddef;
+def plain_set_line_width_op = "setlinewidth" enddef;
+def plain_set_fill_cmyk_op = "setcmykcolor" enddef;
+def plain_set_draw_cmyk_op = "setcmykcolor" enddef;
+def plain_set_line_join_op = "setlinejoin" enddef;
+def plain_set_line_cap_op = "setlinecap" enddef;
+def plain_set_miter_limit_op = "setmiterlimit" enddef;
+def plain_set_dash_op = "setdash" enddef;
+def plain_g_save_op = "gsave" enddef;
+def plain_g_restore_op = "grestore" enddef;
+% ---
+% there is some inconsistency between Corel and AI (it could be said that
+% even between Corel and Corel, and between AI and AI), therefore the code
+% for filling, drawing and clipping operations is somewhat messy...
+% ---
+def close_op = begingroup closed_path:=true; "" endgroup enddef;
+def close_path_op = "h" enddef;
+def move_op = "m" enddef;
+def line_op = "l" enddef;
+def bezi_op = "c" enddef;
+def beg_path_op = "*u" enddef;
+def end_path_op = "*U" enddef;
+let beg_fill_op=beg_path_op;
+def mid_fill_op = "f" enddef;
+def end_fill_op = "*U*f" enddef;
+let beg_draw_op=beg_path_op;
+def mid_draw_op = if closed_path: "s" else: "S" fi enddef;
+def end_draw_op = "*U*d" enddef;
+let beg_clip_op=beg_path_op;
+def prep_clip_op = "W" enddef; % AI-oriented, here just empty
+def do_clip_op = "n" enddef;
+def mid_clip_op =
+ close_path_op & " " & prep_clip_op & " " & do_clip_op
+enddef;
+def end_clip_op = "*U*c" enddef;
+def set_line_width_op = "w" enddef;
+def set_fill_cmyk_op = "k" enddef;
+def set_draw_cmyk_op = "K" enddef;
+def set_line_join_op = "j" enddef;
+def set_line_cap_op = "J" enddef;
+def set_miter_limit_op = "M" enddef;
+def set_dash_op = "d" enddef;
+def g_save_op = "q" enddef;
+def g_restore_op = "Q" enddef;
+% ---
+def mark_null = "/oper_kind -1 def" enddef;
+def mark_fill = "/oper_kind 0 def" enddef;
+def mark_draw = "/oper_kind 1 def" enddef;
+def mark_clip = "/oper_kind 2 def" enddef;
+def check_fill = "0 oper_kind eq" enddef;
+def check_draw = "1 oper_kind eq" enddef;
+def check_clip = "2 oper_kind eq" enddef;
+% ---
+def write_def(expr p,q) =
+ if p<>"": write_PS "/" & p & " {" & q & "} def"; fi
+enddef;
+% ---
+def no_export_write_preamble expr s = pickup pencircle scaled 0.4pt; enddef;
+def normal_write_preamble expr s =
+ message "generating " & s & ".eps";
+ if unknown testing:
+ batchmode; % don't write mess to the terminal
+ fi
+ message ":EPS FILE NAME: " & s;
+ write_PS "%!PS-Adobe-2.0 EPSF-2.0";
+ write_PS "%%Creator: MFTOEPS ver. " & mftoeps_ver;
+ if (known xl_crd) and (known yl_crd) and (known xh_crd) and (known yh_crd):
+ write_PS "%%BoundingBox: " & bp_num(xl_crd) & " " & bp_num(yl_crd)
+ & " " & bp_num(xh_crd) & " " & bp_num(yh_crd);
+ else:
+ xl_crd:=0; xh_crd:=72bp; yl_crd:=0; yh_crd:=72bp;
+ if unknown testing:
+ errorstopmode; % switch temporarily to the usual mode
+ fi
+ message "Unknown bounding box (0 0 72 72 assumed)";
+ if unknown testing:
+ batchmode; % again don't write mess to the terminal
+ fi
+ write_PS "%%BoundingBox: 0 0 72 72";
+ fi
+ write_PS "%%Title: " & s & ".eps";
+ write_PS "%%CreationDate: " & decimal(day) & "." if month<10: & "0" fi
+ & decimal(month) & "." & decimal(year) & " " & decimal(time div 60)
+ & ":" if (time mod 60)<10: & "0" fi & decimal(time mod 60);
+ write_PS "%%DocumentStyle: compatibility "
+ & "(CorelDRAW! & Adobe Illustrator oriented)";
+ write_PS "%%DocumentFonts:";
+ write_PS "%%EndComments";
+ write_PS "%%BeginProlog";
+ write_PS "/mftoeps_export 100 dict def % you may wish to add some entries";
+ write_PS "mftoeps_export begin";
+ write_def (close_op,plain_close_op);
+ write_def (close_path_op,plain_close_op);
+ write_def (move_op,plain_move_op);
+ write_def (bezi_op,plain_bezi_op);
+ write_def (line_op,plain_line_op);
+ write_def (set_fill_cmyk_op,plain_set_fill_cmyk_op);
+ write_def (set_draw_cmyk_op,plain_set_draw_cmyk_op);
+ write_def (beg_path_op,mark_null);
+ write_def (end_path_op,
+ end_fill_op & " " & end_draw_op & " " & end_clip_op);
+ write_def (mid_fill_op,mark_fill);
+ write_def (end_fill_op,check_fill & " {" & plain_fill_op & "} if")
+ closed_path:=true;
+ write_def (mid_draw_op, plain_close_op & " " & mark_draw);
+ closed_path:=false;
+ write_def (mid_draw_op, mark_draw);
+ write_def (end_draw_op,check_draw & " {" & plain_draw_op & "} if")
+ write_def (prep_clip_op,"");
+ write_def (do_clip_op, mark_clip);
+ write_def (end_clip_op,check_clip &
+ " {" & plain_clip_op & " " & plain_new_path_op & "} if");
+ write_def (set_line_width_op,plain_set_line_width_op);
+ write_def (set_line_join_op,plain_set_line_join_op);
+ write_def (set_line_cap_op,plain_set_line_cap_op);
+ write_def (set_miter_limit_op,plain_set_miter_limit_op);
+ write_def (set_dash_op,plain_set_dash_op);
+ write_PS "/setcmykcolor where {pop}";
+ write_PS " {/setcmykcolor {1 sub /mf exch def";
+ write_PS " 3 {mf add neg dup 0 lt {pop 0} if 3 1 roll} repeat";
+ write_PS " setrgbcolor} def} ifelse";
+ write_def (g_save_op,plain_g_save_op);
+ write_def (g_restore_op,plain_g_restore_op);
+ write_PS "/mftoeps_bhook where {pop mftoeps_bhook} {} ifelse";
+ scantokens extra_preamble;
+ write_PS "%%EndProlog";
+ write_PS "%%BeginSetup"; % important structural comment
+ write_PS "%%EndSetup"; % ditto
+ g_save;
+ fix_line_width 0.4pt;
+ fix_fill_cmyk 0,0,0,1;
+ fix_draw_cmyk 0,0,0,1;
+ fix_line_join default_line_join;
+ fix_line_cap default_line_cap;
+ fix_miter_limit default_miter_limit;
+ clipping_level:=0;
+ fix_dash () 0;
+enddef;
+% ---
+def no_export_write_postamble = reset_BB; enddef;
+def normal_write_postamble =
+ forever: exitif clipping_level=0; clip_C; endfor
+ g_restore;
+ write_PS "%%Trailer";
+ write_PS "/mftoeps_ehook where {pop mftoeps_ehook} {} ifelse";
+ scantokens extra_postamble;
+ write_PS "end showpage";
+ if unknown testing:
+ errorstopmode; % switch to the usual mode
+ fi
+ message "";
+ reset_BB;
+enddef;
+% ---
+def g_save = write_PS g_save_op enddef;
+def g_restore = write_PS g_restore_op enddef;
+% ---
+def fix_dash (text t) expr x =
+ def current_dash_array = t enddef; current_dash_offset:=x;
+enddef;
+def set_dash =
+ dash_array_empty:=true;
+ write_PS "["
+ for dash_array:=current_dash_array: if not dash_array_empty: & " " fi
+ & hide(dash_array_empty:=false) bp_num(dash_array)
+ endfor
+ & "] " & bp_num(current_dash_offset) & " " & set_dash_op;
+enddef;
+% ---
+def fix_line_width expr p =
+ current_line_width:=max(p,0); pickup pencircle scaled current_line_width;
+enddef;
+def set_line_width =
+ write_PS bp_num(if known current_line_width: current_line_width
+ else: .5[pen_rt-pen_lft,pen_top-pen_bot] fi) & " " & set_line_width_op;
+enddef;
+% ---
+def fix_line_join expr p =
+ current_line_join:=
+ if (round(p)<0) or (round(p)>2): default_line_join else: round(p) fi;
+enddef;
+def set_line_join =
+ write_PS decimal(if known current_line_join: current_line_join
+ else: default_line_join fi) & " " & set_line_join_op;
+enddef;
+% ---
+def fix_line_cap expr p =
+ current_line_cap:=
+ if (round(p)<0) or (round(p)>2): default_line_cap else: round(p) fi;
+enddef;
+def set_line_cap =
+ write_PS decimal(if known current_line_cap: current_line_cap
+ else: default_line_cap fi) & " " & set_line_cap_op;
+enddef;
+% ---
+def fix_miter_limit expr p =
+ current_miter_limit:=if p<1: default_miter_limit else: p fi;
+enddef;
+def set_miter_limit =
+ write_PS decimal(if known current_miter_limit: current_miter_limit
+ else: default_miter_limit fi) & " " & set_miter_limit_op;
+enddef;
+% ---
+def set_fill_cmyk =
+ write_PS decimal(fill_cyan) & " " & decimal(fill_magenta) &
+ " " & decimal(fill_yellow) & " " & decimal(fill_black) & " " &
+ set_fill_cmyk_op;
+enddef;
+def set_draw_cmyk =
+ write_PS decimal(draw_cyan) & " " & decimal(draw_magenta) &
+ " " & decimal(draw_yellow) & " " & decimal(draw_black) & " " &
+ set_draw_cmyk_op;
+enddef;
+% ---
+vardef norm_color expr c = min(1,max(0,c)) enddef;
+def fix_fill_cmyk text t = % syntax trick
+ fill_cyan:=whatever; fill_magenta:=whatever;
+ fill_yellow:=whatever; fill_black:=whatever;
+ for vv_:=t:
+ if unknown fill_cyan: fill_cyan:=norm_color vv_;
+ elseif unknown fill_magenta: fill_magenta:=norm_color vv_;
+ elseif unknown fill_yellow: fill_yellow:=norm_color vv_;
+ elseif unknown fill_black: fill_black:=norm_color vv_;
+ fi
+ endfor
+enddef;
+def fix_draw_cmyk text t = % syntax trick
+ draw_cyan:=whatever; draw_magenta:=whatever;
+ draw_yellow:=whatever; draw_black:=whatever;
+ for vv_:=t:
+ if unknown draw_cyan: draw_cyan:=norm_color vv_;
+ elseif unknown draw_magenta: draw_magenta:=norm_color vv_;
+ elseif unknown draw_yellow: draw_yellow:=norm_color vv_;
+ elseif unknown draw_black: draw_black:=norm_color vv_;
+ fi
+ endfor
+enddef;
+% ---
+def fix_fill_rgb text t = % syntax trick
+ begingroup
+ save R_,G_,B_;
+ for vv_:=t:
+ if unknown R_: R_:=norm_color vv_;
+ elseif unknown G_: G_:=norm_color vv_;
+ elseif unknown B_: B_:=norm_color vv_;
+ fi
+ endfor
+ convert_rgb_to_cmyk(R_,G_,B_)
+ (fill_cyan, fill_magenta, fill_yellow, fill_black);
+ endgroup
+enddef;
+def fix_draw_rgb text t = % syntax trick
+ begingroup
+ save R_,G_,B_;
+ for vv_:=t:
+ if unknown R_: R_:=norm_color vv_;
+ elseif unknown G_: G_:=norm_color vv_;
+ elseif unknown B_: B_:=norm_color vv_;
+ fi
+ endfor
+ convert_rgb_to_cmyk(R_,G_,B_)
+ (draw_cyan, draw_magenta, draw_yellow, draw_black);
+ endgroup
+enddef;
+% ---
+def convert_rgb_to_cmyk (expr R,G,B)(suffix C,M,Y,K) =
+ begingroup
+ save C_,M_,Y_,K_; C_:=1-R; M_:=1-G; Y_:=1-B; K_:=min(C_,M_,Y_);
+ C:=min(1, max(0,C_-under_color_removal(K_)));
+ M:=min(1, max(0,M_-under_color_removal(K_)));
+ Y:=min(1, max(0,Y_-under_color_removal(K_)));
+ K:=min(1, max(0,black_generation(K_)));
+ endgroup
+enddef;
+% ---
+% DEFAULTS:
+def mftoeps_default text t = % main global defaults
+ forsuffixes S_:=t:
+ if str S_ = "under_color_removal":
+ vardef under_color_removal(expr k) = 0 enddef; % modify if you know better
+ elseif str S_ = "black_generation":
+ vardef black_generation(expr k) = 0 enddef; % ditto
+ elseif str S_ = "default_miter_limit":
+ default_miter_limit:=10; % as in PostScript
+% incidentally, |10bp| would convert to |10.00002| during export at |300dpi|
+ elseif str S_ = "default_line_join": default_line_join:=0; % as in PostScript
+ elseif str S_ = "default_line_cap": default_line_cap:=0; % ditto
+ elseif str S_ = "epsil.ang": epsil.ang:=.1; % in degrees
+ elseif str S_ = "epsil.dist": epsil.dist:=1/10pt; % ca |2/5|pxl at |300dpi|
+ fi
+ endfor
+enddef;
+%
+mftoeps_default under_color_removal, black_generation, default_miter_limit,
+ default_line_join, default_line_cap, epsil.ang, epsil.dist;
+% ---
+endinput;
+%%\end
diff --git a/graphics/MF-PS/progs/0progs.doc b/graphics/MF-PS/progs/0progs.doc
new file mode 100644
index 0000000000..d864a8ed72
--- /dev/null
+++ b/graphics/MF-PS/progs/0progs.doc
@@ -0,0 +1,25 @@
+This file belongs to the MFTOEPS package.
+
+The directory PROGS contains the following files:
+ 0PROGS.DOC this file
+ E2M.BAT canonical DOS batch file for converting EPS files to
+ MF ones; uses AWK
+ M2E.BAT canonical DOS batch file for generating EPS files; uses AWK
+ M2E-ALT.BAT alternative DOS batch file for generating EPS files; uses TeX
+ SPLITEPS.AWK AWK program used by M2E.BAT
+ SPLITEPS.TEX TeX program used by M2E-ALT.BAT
+ TEX.BAT sample DOS batch file calling TeX used by M2E-ALT.BAT
+
+Some of these files may require adjustments to the needs
+of a particular system.
+
+You are entitled to do with these files whatever you wish. If you alter
+a file, however, please remove the line containing the comment:
+
+ `This file belongs to the MFTOEPS package.'
+
+in order to avoid mess.
+
+-----------------------------------------------------------------------------
+
+END OF THE 0PROGS.DOC FILE
diff --git a/graphics/MF-PS/progs/README b/graphics/MF-PS/progs/README
new file mode 120000
index 0000000000..db7eb0690c
--- /dev/null
+++ b/graphics/MF-PS/progs/README
@@ -0,0 +1 @@
+0progs.doc \ No newline at end of file
diff --git a/graphics/MF-PS/progs/e2m.bat b/graphics/MF-PS/progs/e2m.bat
new file mode 100644
index 0000000000..7fec349783
--- /dev/null
+++ b/graphics/MF-PS/progs/e2m.bat
@@ -0,0 +1,11 @@
+:: This file belongs to the MFTOEPS package.
+::
+:: %1 is an input file name WITH extension
+:: %2 is an output file name WITH extension
+::
+:: Software used (change if required):
+:: GAWK.EXE or (better) GAWK32.EXE, ver. 3.0.x
+::
+@echo off
+:: gawk -f epstomf.awk %1 > %2
+gawk32 -f epstomf.awk %1 > %2
diff --git a/graphics/MF-PS/progs/m2e-alt.bat b/graphics/MF-PS/progs/m2e-alt.bat
new file mode 100644
index 0000000000..c96c568f88
--- /dev/null
+++ b/graphics/MF-PS/progs/m2e-alt.bat
@@ -0,0 +1,30 @@
+::
+:: This file belongs to the MFTOEPS package.
+::
+@echo off
+::
+:: %1 is a file name WITHOUT extension
+::
+:: This batch is an alternative to M2E.BAT using TeX rather than AWK
+::
+:: Software used (change if required):
+:: MF386.EXE
+:: TEX.BAT (TEX.BAT calls TeX, because calling TeX may be
+:: configuration-dependent; see sample TEX.BAT)
+:: GFTODVI.EXE
+::
+ mf386 &plain \yeseps:=1; input %1
+ if errorlevel==1 goto EMERG
+ call tex.bat \def\inputname{%1.log}\input spliteps.tex
+ if exist %1.300 goto NOPSMODE
+ goto CLEANUP
+:NOPSMODE
+:: `no_export_level' was used for some reason (error?)...
+ gftodvi %1.300
+ if exist %1.300 del %1.300
+ if exist %1.tfm del %1.tfm
+ if exist %1.eps del %1.eps
+:CLEANUP
+ if exist spliteps.log del spliteps.log
+:: del %1.log
+:EMERG
diff --git a/graphics/MF-PS/progs/m2e.bat b/graphics/MF-PS/progs/m2e.bat
new file mode 100644
index 0000000000..53a5aad72a
--- /dev/null
+++ b/graphics/MF-PS/progs/m2e.bat
@@ -0,0 +1,26 @@
+:: This file belongs to the MFTOEPS package.
+::
+@echo off
+::
+:: %1 is a file name WITHOUT extension
+::
+:: Software used (change if required):
+:: MF386.EXE
+:: GAWK.EXE or (better) GAWK32.EXE, ver. 3.0.x
+:: GFTODVI.EXE
+::
+ mf386 &plain \yeseps:=1; input %1
+ if errorlevel==1 goto EMERG
+:: gawk -f spliteps.awk %1.log
+ gawk32 -f spliteps.awk %1.log
+ if exist %1.300 goto NOPSMODE
+ goto CLEANUP
+:NOPSMODE
+:: `no_export_level' was used for some reason (error?)...
+ gftodvi %1.300
+ if exist %1.300 del %1.300
+ if exist %1.tfm del %1.tfm
+ if exist %1.eps del %1.eps
+:CLEANUP
+:: del %1.log
+:EMERG
diff --git a/graphics/MF-PS/progs/spliteps.awk b/graphics/MF-PS/progs/spliteps.awk
new file mode 100644
index 0000000000..f14733c2a6
--- /dev/null
+++ b/graphics/MF-PS/progs/spliteps.awk
@@ -0,0 +1,9 @@
+#
+# This file belongs to the MFTOEPS package.
+#
+# AWK program to be used by M2E.BAT
+#
+BEGIN {N=""}
+$0 ~ /^:EPS FILE NAME: / {
+ if (NF==3) {N="vicar.eps"} else {N=$NF ".eps"} print "extracting " N}
+$0 ~ /^:PS: / {print substr($0,6) > N}
diff --git a/graphics/MF-PS/progs/spliteps.tex b/graphics/MF-PS/progs/spliteps.tex
new file mode 100644
index 0000000000..f1503eaeb6
--- /dev/null
+++ b/graphics/MF-PS/progs/spliteps.tex
@@ -0,0 +1,83 @@
+%
+% This file belongs to the MFTOEPS package.
+%
+% TeX file approximately emulating the following AWK program:
+% BEGIN {N=""}
+% $0 ~ /^:EPS FILE NAME: / {
+% if (NF==3) {N="vicar.eps"} else {N=$NF ".eps"} print "extracting " N}
+% $0 ~ /^:PS: / {print substr($0,6) > N}
+% (see SPLITEPS.AWK)
+%
+% REMARK: it was a suggestion of Phil Taylor to use TeX instead of AWK.
+
+\ifx\inputname\undefined \errmessage{\noexpand\inputname NOT DEFINED}\fi
+\newread\currentinput \immediate\openin\currentinput\inputname\relax
+\ifeof\currentinput \errmessage{FILE \inputname\space NOT FOUND}\fi
+
+\newwrite\currentoutput
+
+\newif\ifcontinueloop
+\newif\ifoutputopen \outputopenfalse
+
+\def\EPSfirstline{EPS FILE NAME}
+\def\EPSline{PS}
+
+\def\gobblespace#1{#1}
+\def\truncatekey#1:#2:#3\relax{%
+ \def\linecontents{#3}%
+ \ifx\linecontents\empty
+ \else
+ \edef\linecontents{\expandafter\gobblespace\linecontents}%
+ \fi}
+
+\long\def\getkey#1:#2:{\gdef\prekey{#1}\gdef\key{#2}}
+
+\def\getline{%
+ \immediate\read\currentinput to \currentline \edef\currentline{\currentline}%
+ \setbox0\hbox{\expandafter\getkey\currentline::}}
+
+\def\fixnewoutputname{%
+ \expandafter\truncatekey\currentline\relax
+ \edef\outputname{\linecontents}%
+ \ifx\outputname\empty \edef\outputname{vicar.eps }%
+ \else \edef\outputname{\outputname.eps }\fi
+ \immediate\write16{extracting \outputname}}
+
+\def\optionallyopenout{%
+ \ifx\key\EPSfirstline
+ \optionallycloseout \fixnewoutputname
+ \immediate\openout\currentoutput\outputname\relax
+ \ifeof\currentoutput
+ \errmessage{CANNOT OPEN \outputname FOR WRITING}\global\outputopenfalse
+ \else
+ \global\outputopentrue
+ \fi
+ \fi}
+
+\def\optionallycloseout{\ifoutputopen \immediate\closeout\currentoutput \fi}
+
+\def\optionallyputline{%
+ \ifx\key\EPSline
+ \expandafter\truncatekey\currentline\relax
+ \immediate\write\currentoutput{\linecontents}%
+ \fi}
+
+\def\checklooping{\continuelooptrue\ifeof\currentinput\continueloopfalse\fi}
+
+\def\neutralizecatcodes{%
+ \catcode`\\12 \catcode`\%12 \catcode`\&12 \catcode`\_12
+ \catcode`\^12 \catcode`\{12 \catcode`\}12 \catcode`\/12 }
+
+\def\getlines{%
+ \begingroup
+ \endlinechar=-1
+ \neutralizecatcodes
+ \loop
+ \getline \ifx\prekey\empty \optionallyopenout \optionallyputline \fi
+ \checklooping \ifcontinueloop \repeat
+ \endgroup
+ \optionallycloseout}
+
+\getlines
+
+\end
diff --git a/graphics/MF-PS/progs/tex.bat b/graphics/MF-PS/progs/tex.bat
new file mode 100644
index 0000000000..58b4a5be5c
--- /dev/null
+++ b/graphics/MF-PS/progs/tex.bat
@@ -0,0 +1,8 @@
+::
+:: This file belongs to the MFTOEPS package.
+::
+@echo off
+::
+:: sample batch file calling TeX (see M2E-ALT.BAT)
+::
+tex386 /mt19000 /mf150000 &plain %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/graphics/MF-PS/roex/0roex.doc b/graphics/MF-PS/roex/0roex.doc
new file mode 100644
index 0000000000..0887e2df6c
--- /dev/null
+++ b/graphics/MF-PS/roex/0roex.doc
@@ -0,0 +1,36 @@
+This file belongs to the ROEX package.
+
+-----------------------------------------------------------------------------
+
+OVERVIEW
+
+The package ROEX belongs to the public domain. You are entitled to do with
+the files of which it consists whatever you wish. If you alter a file,
+however, please remove the line containing the comment
+
+ `This file belongs to the ROEX package.'
+
+in order to avoid a mess.
+
+The ROEX.MF file contains a set of METAFONT macros accomplishing the
+task of removing overlaps and expanding strokes. The algorithm was
+suggested by Stefan Soko\l{}owski, the implementation was done
+by Bogus\l{}aw Jackowski, Piotr Pianowski and Marek Ry\'cko.
+
+The operations of removing overlaps and expanding strokes are especially
+useful in context of PostScript, hence all examples make use of the MFTOEPS
+package; however, PostScript here is not essential.
+
+Detailed description of the macros can be found in the file ROEX.MF,
+examples of using the package can be found in the subdirectory ROEXSAMP.
+
+-----------------------------------------------------------------------------
+
+ENCOURAGEMENT
+
+The inspection of the source code of the ROEX.MF program may reveal
+a few more useful macros.
+
+-----------------------------------------------------------------------------
+
+END OF THE 0ROEX.DOC FILE
diff --git a/graphics/MF-PS/roex/README b/graphics/MF-PS/roex/README
new file mode 120000
index 0000000000..305b1e1363
--- /dev/null
+++ b/graphics/MF-PS/roex/README
@@ -0,0 +1 @@
+0roex.doc \ No newline at end of file
diff --git a/graphics/MF-PS/roex/roex.mf b/graphics/MF-PS/roex/roex.mf
new file mode 100644
index 0000000000..dbf6f8e35d
--- /dev/null
+++ b/graphics/MF-PS/roex/roex.mf
@@ -0,0 +1,1756 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%%% ---------------------------------------------------------------------
+%%%% MFT formatting commands
+%%%% ---------------------------------------------------------------------
+%%% length quicksort
+%%% length cycle zang pos_turn neg_turn
+%%% good enc
+%%% labels makelabel
+%%% length make_cycle make_join make_cyclic_join make_end make_edge
+%%% point predir postdir upredir upostdir udir
+%%% dotprod det
+%%% subpath pos_subpath neg_subpath
+%%% message info_ro info_es
+%%% draw roex_default
+%%% -- &&
+%%%% ---------------------------------------------------------------------
+%%%% \TeX formatting commands
+%%%% ---------------------------------------------------------------------
+%%\vsize245mm
+%%\font\titfnt cmtt10 at 48 pt
+%%{\let\makefootline\empty \let\makeheadline\empty
+%%\vglue0ptplus1fill
+%%\centerline{\titfnt ROEX.MF}
+%%\bigskip
+%%\centerline{ver. 0.56 (Wednesday, October 25th, 1995)}
+%%\vfill\vfill\eject}
+%% % ---
+%% \vsize 245mm
+%% % an innocent formatting trick: the underscore character ending a name
+%% % will be typeset as an superscript asterisk
+%% \let\oriunderscore\_
+%% \newif\ifbgroupopen\bgroupopenfalse
+%% \def\altdblbackslash#1{\bgroup\bgroupopentrue\it#1}
+%% \def\optegroup{\ifbgroupopen\egroup\fi}
+%% \def\underscoreasasterisk#1{%
+%% \ifx#1\relax\optegroup^*\else\oriunderscore#1\fi}
+%% \def\\#1{%
+%% \let\_\underscoreasasterisk
+%% \altdblbackslash{#1\relax}\optegroup
+%% \let\_\oriunderscore}
+%% % ---
+%% \def\dblhyph{--}
+%% \def\8#1{\def\eightparm{#1}\mathrel{\mathcode`\.="8000 \mathcode`\-="8000
+%% \ifx\eightparm\dblhyph\setbox\shorthyf\hbox{\bf -\kern-.05em}\fi%
+%% #1\unkern}} % `..' and `--'
+%% % ---
+%% \def\MP{{\tenlogo META}\-{\tenlogo POST}}
+% ------------------------------------------------------------------------
+% This is ROEX.MF file containing \MF definitions implementing
+% operations known as `remove overlap' and `expand stroke'.
+% ------------------------------------------------------------------------
+% Authors: \bf{}B. Jackowski, P. Pianowski, M. Ry\'cko \& S. Soko\l{}owski
+% ------------------------------------------------------------------------
+% H I S T O R Y
+% ver. 0.1 (1 / 9 VI 1994):
+% * incunabula version
+% ver. 0.5 (15 VIII / 1 IX 1995):
+% * pioneer version, released during the 9th Euro\TeX conference in Arnhem
+% ver. 0.55 (26 IX 1995):
+% * if a single path is an argument to |remove_overlap|, removing
+% of self-overlaps is performed, hence several adjustments, most
+% significant changes were introduced in |is_far_enough| and
+% |intersect_two_segments|; this ismprovement is, in fact, a prelude
+% towards a more general approach
+% * a bug trap added in |clean_path|
+% * positioning of labels not forced in |mark_nodes|
+% * |quicksort| more flexible
+% * more statistics available (optionally) in |find_minimal_secant|
+% * displaying information changed
+% * \TeX formatting comments collected at the beginning of the file
+% * a result of mental laps corrected in |build_node_structure|
+% (minimal secant has nothing to do with minimal distance between nodes)
+% * a silly bug removed in |prepare_input_data| (|W| instead of |W_|)
+% This version was released during the CyrTUG-95 meeting in Moscow
+% ver. 0.56 (27 X 1995):
+% * comments adjusted to a new distribution
+% * the name |miter_limit| changed to |miter_size| in order to avoid
+% misunderstanding, as in this implementation it is a dimen, while
+% in PostScript it is a dimensionless quantity
+% ------------------------------------------------------------------------
+% S Y N O P S I S
+% ------------------------------------------------------------------------
+%
+% Such operations as `remove overlap' and `expand stroke' are perhaps
+% particularly useful in the contex of exporting data from \MF to other
+% languages, e.g., to PostScript or HP-GL. Therefore the file ROEX.MF has
+% been included into the MFTOEPS package (which accomplishes export from \MF
+% to Encapsulated PostScript), although it can be used by ``normal'' \MF
+% users, too. Therefore our favourite macros (e.g., |pos_turn|, |neg_turn|,
+% |make_list|), are defined identically in both ROEX and MFTOEPS.
+%
+% We hope that tiny adjustments, if any, should be sufficient for transforming
+% the macros to the form accepted by both \MF and \MP.
+%
+% Sample \MF programs (i.e., simple examples) illustrating the use of the
+% ``interface'' macros, i.e., |remove_overlap|, |expand_stroke| and
+% |change_weight|, can be found in a subdirectory ROEXSAMP. It is instructive
+% to generate EPS files and then to play around with the results using
+% CorelDRAW! or Adobe Illustrator.
+%
+%
+% REMOVING OVERLAPS
+%
+% The command |remove_overlap_| requires three parameters. The first
+% parameter is a list of paths to be processed; the paths are assumed to
+% have a non-zero |turningnumber| and no self intersecting points (no
+% checking is performed, except that non-cyclic paths are ignored).
+% The second parameter is a list (possibly empty) of weights assigned
+% to paths; more exactly, it is a list of pairs |(i,w.i)|, where |i| is
+% the order number of a path and |w.i| is the respective weight.
+% If the weight is not specified it is assumed to be equal to |1|.
+% The last parameter is a suffix, i.e., the name of the resulting data
+% structure; given a suffix is |R|, |R.num| is the number of the resulting
+% paths, and |R1|, |R2|, ..., |R[R.num]| are the paths. If the suffix
+% contains an index, e.g., |P[x]q|, the user is responsible for providing
+% appropriate declarations prior to calling |remove_overlap|,
+% in this case: |numeric P[\\]q.num; path P[\\]q[\\]|. If a variable
+% |append_results| is assigned a definite value (by default it is undefined),
+% |R.num| is not zeroed at the stage of initialisation, thus the results
+% are accumulated (see example ROES-02.MF in the subdirectory ROEXSAMP).
+%
+% The algorithm assumes that a path |p| fills its interior with the colour
+% |w*turningnumber(p)|, where |w| is the weight assigned to |p|. If an
+% area is coloured by several paths, the colors are summed up. The user
+% decides which areas are the resulting ones. By default, these are areas
+% which have the interior painted with a colour $\ge1$ and the exterior
+% painted with a colour $\le0$. There is a two-parameter function
+% (parameters are numbers) that can be redefined by a user, |good_colors|,
+% which governs the decision. The user is responsible for a proper definition
+% of this function (the formula |good_colors(m,n) and good_colors(n,m)| must
+% be false; cf. the default definition of |good_colors| at the end of this
+% file). There is also a variable |background_color|, by default equal to |0|,
+% which determines the colour of the Euclidian plane. One more function that
+% is meant to be redefined by the user, if needed, is one-parameter function
+% |touch_path|; the function is applied to every input path at the stage of
+% initialisation, and can be used, e.g., for adjusting the direction of paths
+% (cf. example RO-04.MF in the subdirectory ROEXSAMP).
+%
+% The orientation of paths generated by the |remove_overlap| macro is defined
+% in such a way that in order to fill the resulting figure the internal
+% variable |turningcheck| should be set to zero prior to using the |fill|
+% command.
+%
+% Examples:
+% Assume that paths |A|, |B| and |C| are defined as follow (say, |w=h=1cm|):
+% |A=unitsquare xscaled 1/5w yscaled h shifted (2/5w,0);|
+% |B=A rotatedaround((1/2w,1/2h), 60);|
+% |C=B rotatedaround((1/2w,1/2h), 60);|
+% Calling
+% |remove_overlap (A,B,C) () R;|
+% will result in generating a single path |R1| (|R.num=1|) of a six-arm
+% propeller shape. Adding one more path:
+% |D=reverse fullcircle scaled 3/4w shifted (1/2w,1/2h);|
+% and calling
+% |remove_overlap (A,B,C,D) ((4,2)) R;|
+% (|D| has weight |=2|) will result in generating seven objects: six
+% ``tips'' of a propeler and a regular hexagon in the center. Try to guess
+% what would be the result of
+% |remove_overlap (A,B,C,D) () R;|
+% Not all paths need to intersect. For example, the following set of paths
+% |A=fullcircle scaled w shifted (1/2w,1/2h);|
+% |B=reverse unitsquare xscaled 1/5w yscaled 3/5w shifted (2/5w,1/5w);|
+% |C=B rotatedaround((1/2w,1/2h), 90);|
+% after calling
+% |remove_overlap (A,B,C) () R;|
+% will yield a circle surrounding a white cross. Since the orientation
+% of the resulting paths is important here, the |fill| commands should be
+% preceded by
+% |interim turningcheck:=0;|
+% assignment.
+%
+%
+% EXPANDING STROKES
+%
+% Expanding stroke means finding the trace of the outline of an imaginary pen
+% moving along a path. There are two commands accomplishing expanding stroke:
+% |expand_stroke| and |change_weight|. Both make use of the essentially the
+% same algorithm, except that the latter finds only one edge and ignores
+% non-cyclic paths. Both commands require three parameters: first and third
+% are analogous to the parameters of the |expand_stroke| macro (see above),
+% the second denotes the radius (not diameter) of the circular pen.
+% The algorithm works in such a way that the result of the |expand_stroke|
+% does not depend on the direction of a path for cyclic paths, namely,
+% the outer edge is always positively directed and the inner is negatively
+% directed, provided the radius is positive; if the radius is negative,
+% the outer edge is negatively directed and the inner one---positively.
+% For non-cyclic paths positive radius yields positively directed resulting
+% paths, negative radius---negatively oriented paths. Although the macro
+% |change_weight| is subdued to the same rules, the result depends both
+% on the direction of a path and on the sign of a radius. Let |t| and |r|
+% denote the turning number and the radius, respectively; there are
+% four cases:
+% 1) |t>0| and |r>0|: the resulting path is an outer edge positively
+% directed,
+% 2) |t>0| and |r<0|: the resulting path is an inner edge positively
+% directed,
+% 3) |t<0| and |r>0|: the resulting path is an inner edge negatively
+% directed,
+% 4) |t<0| and |r<0|: the resulting path is an outer edge negatively
+% directed.
+% Following PostScript, we introduced three variables which govern the shape
+% of joins and ends: |join_kind| (corresponds to |setlinejoin|), |end_kind|
+% (corresponds to |setlinecap|) and |miter_size| (corresponds, as the name
+% suggest, to |setmiterlimit|; however, here |miter_size| is a dimen,
+% while in PostScript miter limit is a dimensionless quantity).
+% Currently both |join_kind| and |end_kind| can receive value |0| or |1|,
+% while in PostScript value |2| is also admissible. (The latter option
+% will perhaps be included also into the ROEX package some day, but more
+% tempting is the implementation of extrapolated non-linear joins.)
+% Since the interpretation of |miter_size| (dimen) is slightly different than
+% the interpretation of |miter_limit| (a number), |miter_size| must merely
+% be non-negative, while |miter_limit| must be greater than or equal to $1$.
+% Roughly speaking, value |0| for |join_kind| and |end_kind| denotes cusp
+% joins, cut if necessary at miter limit; value |1| denotes rounded rounded
+% joins (for details see, e.g., ``PostScript Language Reference Manual,''
+% second ed., Addison-Wesley Publishing Company, Ltd.).
+%
+% Example:
+% Assume that a path |A| is simply a square (say, |w=h=1cm|):
+% |A=unitsquare scaled w;|
+% After calling
+% |expand_stroke(A)(1mm)R;|
+% |R1| is a positively directed square of side |12mm|, and |R2| is
+% negatively directed square of side |8mm|.
+% ------------------------------------------------------------------------
+% C A V E A T S , H I N T S A N D C O M M E N T S
+% * The employed algorithms expect that the results are well defined;
+% if the data are weird (e.g., self-loooping path are supplied)
+% the results, if any, may be weird as well.
+% * The case of curves partially overlapping is not handled and, frankly
+% speaking, we have no idea how to implement it efficiently and robustly;
+% if there are such pairs of paths in the input data, the algorithm almost
+% certainly will not produce good results.
+% * Only circular pens are implemented so far.
+% * Be aware of rounding errors, they may cause unpredictable results;
+% in some cases increasing accuracy by using a higher resolution may
+% help, but more adequate seems to be preparing better data (cf. the
+% program RO-07.MF in the subdirectory ROEXSAMP).
+% * Comments in the code are meant primarily for the authors; the user
+% is kindly requested not to complain fiercely if they are of a little
+% use to her/him.
+% * Unfortunately, \MF has no error-handling facility, hence a lot of
+% ``bug traps'' can be found in the code; messages issued in the case
+% of falling into such a trap are rather useless if you don't know the
+% details of the algorithm; this part of the program is certainly to be
+% improved; usually the error help says ``Better stop now! Algorithm
+% failed'' and this advice should be followed; in practice this means that
+% \MF is not able to recognize the details of the picture because of
+% very close nodes (intersection points).
+% * Usually, the first stage of removing overlaps (finding all intersection
+% points) is the longest one, the more segments paths have the longer it
+% lasts; a pity that \MF has no built-in function informing about all
+% intersection points/times of two B\'ezier curves.
+% * Improper definition of |good_colors| may result in erroneous behaviour of
+% the algorithm.
+% * One peculiar case is considered by the expanding stroke algorithm,
+% namely cyclic path of length 2; some more cases might have been taken
+% into account...
+% * There remain a lot of unsolved problems with numerical instability
+% connected with detecting tangent and close points.
+% * In The \MF{}book, p. 229, D. E. Knuth writes:
+% ``...tiny little loops won't hurt anything if you are filling cycles
+% in the correct direction.''
+% Cf. also preceding dangerous band paragraph and exercise on pp. 228--229.
+% ROEX does much more complex things with paths than merely filling them,
+% hence tiny loops may cause some mess, the more so as the built-in
+% function |turningnumber| is very sensitive to such loops, e.g., it may
+% happen that |turningnumber(p)=1| while |turningnumber(reverse p)=0|
+% (cf. example RO-6.MF in the subdirectory ROEXSAMP); hence a hopefully
+% more robust (from the point of view of this application) function
+% is used, |check_turn|, which makes use of \MF's |fill| operation.
+% * There remain several suboptimal algorithms employed, partially on
+% purpose: less efficient algorithms are usually (although not necessarily)
+% more comprehensible and flexible (easier to modify), which is important
+% at the stage of developing a program.
+% * Parameters that may have influence on the process of removing
+% overlaps are |epsil.time|, |epsil.ang| (in degrees), |epsil.dist| (in
+% resolution-dependent units), and |max_idx|; the choice of good default
+% values will need some practice.
+% * Incompatible modifications may come, although we shall do our best
+% to avoid them.
+% ------------------------------------------------------------------------
+% We follow the naming convention of The \MF{}book:
+% ``Private tokens always end with the underscore character.''
+% Since the underscore is a rather illegible character, in a ``neat''
+% printing (using MFT utility) it will appear as an superscript asterisk.
+% ------------------------------------------------------------------------
+% D E F I N I T I O N S
+% ------------------------------------------------------------------------
+% UNIVERSAL MACROS:
+% ---
+% Without the following redefinition:
+def -- = {curl 1} .. tension (1+eps) .. {curl 1} enddef;
+% the result of |p intersectiontimes reverse p|, where |p=(a,b)--(a+3c,b+3d)|,
+% |a|, |b|, |c|, |d| are arbitrary (sic!) \MF's numbers, yields the result
+% |(1/2,1/2)|, which contradicts the statement preceding the exercise 14.17
+% on the page 137 of The \MF{}book. Since it is no longer a ``standard''
+% macro, its formatting is slightly modified.
+% ---
+%%% length ]]] ]]]]
+%%% ; ]
+def ]]] = ] ] ] enddef;
+def ]]]] = ] ] ] ] enddef; % right brackets should be loners, indeed
+%%% ) ] ]] ]]] ]]]]
+% ---
+vardef distance(expr za,zb) = length(za-zb) enddef; % in fact, an alias
+% ---
+vardef interval(expr ta,tb,p) =
+ save ta_,tb_;
+ if cycle p:
+ ta_:=ta mod length(p); tb_:=tb mod length(p);
+ min(length(p)-abs(ta_-tb_), abs(ta_-tb_))
+ else:
+ ta_:=min(max(0,ta),length(p)); tb_:=min(max(0,tb),length(p));
+ abs(ta_-tb_)
+ fi
+enddef;
+% ---
+def make_list(expr k,l) suffix s =
+ for i_:=k upto l: if i_>k: , fi \\ s[i_] endfor
+enddef;
+% ---
+vardef dec_pair(expr z) =
+ "(" & decimal(xpart z) & "," & decimal(ypart z) & ")"
+enddef;
+% ---
+primarydef u det v = % dual operation to |dotprod|
+ (xpart u * ypart v - xpart v * ypart u)
+enddef;
+% ---
+vardef zang(expr u,v) = % useful during testing
+% computes the angle form |u| to |v| (useful for testing)
+ angle(u dotprod v,u det v) mod 360 % CAVEAT! rounding errors
+enddef;
+% ---
+vardef turn_ang(expr za,zb) = % more robust version of |zang|
+% The idea of computing the turn angle is based on the following observation:
+% |z reflectedabout (origin,right)=1/z| for a complex number |z| such that
+% |abs(z)=1|; recall also that multiplication of complex numbers
+% (|zscaled| operation) implies addition of their angle arguments.
+ if (abs(za)>=epsil.len) and (abs(zb)>=epsil.len): % |eps| may be not enough
+ angle(unitvector(za) zscaled (unitvector(zb) reflectedabout (origin,right)))
+ else: whatever fi
+enddef;
+% ---
+def predir expr t of p = ((point t of p)-(precontrol t of p)) enddef;
+def postdir expr t of p = ((postcontrol t of p)-(point t of p)) enddef;
+def udir expr t of p = unitvector(direction t of p) enddef;
+def upredir expr t of p = unitvector(predir t of p) enddef;
+def upostdir expr t of p = unitvector(postdir t of p) enddef;
+% ---
+vardef pos_turn primary p =
+ interim autorounding:=0;
+ if check_turn(p)=0: show p;
+ errhelp "I will leave the path intact, continue with crossed fingers.";
+ errmessage "Cannot make positive turn (check_turn=0)";
+ elseif check_turn(p)<0: reverse fi \\ p
+enddef;
+% ---
+vardef neg_turn primary p =
+ interim autorounding:=0;
+ if check_turn(p)=0: show p;
+ errhelp "I will leave the path intact, continue with crossed fingers.";
+ errmessage "Cannot make negative turn (check_turn=0)";
+ elseif check_turn(p)>0: reverse fi \\ p
+enddef;
+% ---
+vardef check_turn primary p = % seems more adequate than |turningnumber|
+% |epsilon|=|totalweight currentpicture| after |fill unitsquare|,
+% |eps/epsilon=32|, i.e., we admit accuracy of 32 pixels (isn't it too many?)
+ save r_,currentpicture; picture currentpicture;
+ interim turningcheck:=0; interim autorounding:=0;
+ currentpicture:=nullpicture; fill p; r_:=totalweight(currentpicture);
+ if r_>eps: 1 elseif r_<-eps: -1 else: turningnumber(p) fi
+enddef;
+% ---
+def check_embedding(expr a,b)(suffix res) =
+begingroup
+% see comment in |check_turn|
+ save napb_,panb_,currentpicture; picture currentpicture;
+ interim turningcheck:=0; interim autorounding:=0;
+ currentpicture:=nullpicture; fill pos_turn a; fill neg_turn b; cullit;
+ panb_:=totalweight currentpicture;
+ currentpicture:=nullpicture; fill neg_turn a; fill pos_turn b; cullit;
+ napb_:=totalweight currentpicture;
+ if (panb_<eps) and (napb_<>0): res:=1; % $a \subset b$
+ elseif (panb_<>0) and (napb_<eps): res:=2; % $b \subset a$
+ else: res:=0; fi % undefined result
+endgroup
+enddef;
+% ---
+vardef pos_subpath expr z of p =
+ if not cycle p: subpath z of p
+ else:
+ if xpart(z)<=ypart(z): subpath z of p
+ else: subpath (xpart(z),ypart(z)+length(p)) of p
+ fi
+ fi
+enddef;
+% ---
+vardef neg_subpath expr z of p =
+ if not cycle p: subpath z of p
+ else: reverse(pos_subpath (ypart z,xpart z) of p) fi
+enddef;
+% ---
+tertiarydef p && q = % |length(p)>0|
+ (subpath(0,length(p)-1) of p) ..
+ controls (postcontrol length(p)-1 of p) and (precontrol length(p) of p)
+ .. q
+enddef;
+% ---
+def make_cycle expr p = % |length(p)>0|
+ (subpath(0,length(p)-1) of p) ..
+ controls (postcontrol length(p)-1 of p) and (precontrol length(p) of p)
+ .. cycle
+enddef;
+% ---
+vardef is_line(expr B) =
+% checks if a B\'ezier segment |B| is an almost straight line;
+% recall that |z reflectedabout (origin,right)=1/z| for a complex
+% number |z| such that |length(z)=1|; recall also that the multiplication
+% of complex numbers (|zscale| operation) implies the addition of
+% their angle arguments
+ save pa_,pb_,pc_,pd_,ba_,da_,dc_; pair pa_,pb_,pc_,pd_,ba_,da_,dc_;
+ pa_:=point 0 of B; pd_:=point 1 of B;
+ if distance(pa_,pd_)<epsil.dist:
+ false % either really not a line or an uncertain situation (rounding errors)
+ else:
+ da_=unitvector(pd_-pa_) reflectedabout (origin,right);
+ pb_:=postcontrol 0 of B; if distance(pa_,pb_)<epsil.dist: pb_:=pa_; fi
+ pc_:=precontrol 1 of B; if distance(pd_,pc_)<epsil.dist: pc_:=pd_; fi
+ if (pa_=pb_) and (pc_=pd_): true
+ elseif (pa_=pb_):
+ dc_=unitvector(pd_-pc_); abs(angle(dc_ zscaled da_))<epsil.ang
+ elseif (pc_=pd_):
+ ba_=unitvector(pb_-pa_); abs(angle(ba_ zscaled da_))<epsil.ang
+ else:
+ ba_=unitvector(pb_-pa_); dc_=unitvector(pd_-pc_);
+ (abs(angle(ba_ zscaled da_))<epsil.ang)
+ and (abs(angle(dc_ zscaled da_))<epsil.ang)
+ fi
+ fi
+enddef;
+% ---
+vardef is_tiny_bez(expr B) =
+% checks if B\'ezier segment |B| is negligibly small
+ (distance((postcontrol 0 of B),(point 0 of B))<epsil.dist)
+ and (distance((precontrol 1 of B),(point 0 of B))<epsil.dist)
+ and (distance((point 1 of B),(point 0 of B))<epsil.dist)
+enddef;
+% ---
+vardef are_parallel(expr B,C) =
+% checks if B\'ezier segments |B| and |C| are linear and parallel
+save a_;
+ if is_line(B) and is_line(C):
+ a_:=turn_ang((point 0 of B)-(point 1 of B),(point 0 of C)-(point 1 of C));
+ (if known a_: abs(a_)<epsil.ang else: false fi)
+ else: false fi
+enddef;
+% ---
+vardef tidy_lines(expr P) =
+% converts almost linear segments of a path |P| into a ``tidy'' lines (|--|)
+ save B_; path B_;
+ for i_:=1 upto length(P): if i_>1: & fi
+ hide(B_:=subpath (i_-1,i_) of P)
+ if is_line(B_): ((point 0 of B_)--(point 1 of B_)) else: B_ fi
+ endfor if cycle P: & cycle fi
+enddef;
+% ---
+def add_bez(expr ta,tb, p) =
+ .. controls (postcontrol ta of p) and (precontrol tb of p) .. (point tb of p)
+enddef;
+% ---
+vardef clean_path(expr P) =
+% this routine joins together colinear neighbouring segments and removes
+% ``tiny'' edges of a cyclic path |P| (performed at the end of removing
+% overlaps and expanding stroke); since some nodes may become ``midline''
+% ones after cleaning, the operation is performed twice
+ if cycle P:
+ save P_,for_del_,not_del_,i_,j_; path P_;
+% mark all deletable nodes and one non-deletable node:
+ for i_:=0 upto length(P)-1:
+ if are_parallel(subpath (i_-1,i_) of P,subpath (i_,i_+1) of P)
+ or is_tiny_bez(subpath(i_-1,i_) of P):
+ for_del_[i_]:=1;
+ else:
+ not_del_:=i_;
+ fi
+ endfor;
+% BUG TRAP:
+ if unknown not_del_:
+ err_helpless;
+ errmessage "ROEX ERROR: all nodes deleted during path cleaning";
+ fi
+% delete nodes:
+ i_:=j_:=not_del_; % we start with |not_del_|: one of not deleted points
+ P_:=(point j_ of P)
+ forever:
+% invariant: |i_| recent not deleted point, |j_| current point
+ hide(j_:=(j_+1) mod length(P))
+ if unknown for_del_[j_]: add_bez(i_,j_,P) \\ hide(i_:=j_) fi
+ exitif j_=not_del_;
+ endfor & cycle;
+ tidy_lines(P_)
+ else: P fi
+enddef;
+% ---
+vardef is_less(expr a,b) = (a<b) enddef;
+vardef quicksort@#(expr ii,jj)(suffix s)(text t) =
+% sorts |@#.s[ii..jj]| along with |@#.$[ii..jj]| for |$| in |t|,
+% using Tony Hoare's ``quick sort'' method; suffix |s| must must not occur
+% in the |t| list (no checking is performed); if both |s| and |t| are empty,
+% |t| is ignored.
+% REMARK 1: the algorithm has no explicit recursion, because of \MF's limits
+% on recursion level.
+% REMARK 2: the algorithm, of course, is not stable, i.e., it does not
+% preserve the order of equal items, but it does not matter here
+ save i_,j_,k_,l_,cell_,stack_,incl_t_; boolean incl_t_;
+ pair stack_[\\]; stack_.lev:=0; stack_[incr stack_.lev]:=(ii,jj);
+ i_:=0; for $:=t: i_:=i_+1; endfor % ``measure'' |t|-list
+ incl_t_:=(str s <> "") or ((str s = "") and (i_<>0));
+ forsuffixes $:= s if incl_t_: , t fi:
+ if numeric @#.$[ii]: numeric cell_.$;
+ elseif string @#.$[ii]: string cell_.$;
+ elseif boolean @#.$[ii]: boolean cell_.$;
+ fi
+ endfor
+ forever:
+ exitif stack_.lev<=0;
+ numeric i_,j_; (i_,j_)=stack_[stack_.lev]; stack_.lev:=stack_.lev-1;
+ if i_<j_:
+ forsuffixes $:= s if incl_t_: , t fi: cell_.$:=@#.$[i_]; endfor
+ l_:=i_;
+ for k_:=i_+1 upto j_:
+ if is_less(@#.s[k_],cell_.s):
+ forsuffixes $:=s if incl_t_: , t fi:
+ @#.$[l_]:=@#.$[k_]; @#.$[k_]:=@#.$[l_+1];
+ endfor
+ l_:=l_+1;
+ fi
+ endfor
+ forsuffixes $:= s if incl_t_: , t fi: @#.$[l_]:=cell_.$; endfor
+ stack_[incr stack_.lev]:=(i_,l_-1); stack_[incr stack_.lev]:=(l_+1,j_);
+ fi
+ endfor
+enddef;
+% ---
+% R-O MACROS:
+% ---
+% visualising macros (useful for testing):
+% ---
+def mark_nodes =
+ if proofing>0:
+ for i_:=1 upto NODE_.num:
+ makelabel(decimal(i_) & ":" & decimal(NODE_.pth[i_]),
+ point TIME_[NODE_.pth[i_]]tim[NODE_.tim[i_]] of PATH_[NODE_.pth[i_]]);
+ endfor
+ fi
+enddef;
+% ---
+def mark_area(expr i) =
+begingroup
+ save j_,v_; j_:=i; mark_edge(j_); v_[j_]:=0;
+ forever: j_:=EDGE_.out[j_]; exitif (j_=i) or (known v_.emerg);
+ if known v_[j_]: v_.emerg:=0; else: mark_edge(j_); v_[j_]:=0; fi
+ endfor
+endgroup
+enddef;
+% ---
+def mark_edge(expr i) =
+begingroup
+ if proofing>0:
+ save currentpen, currentpen_path; pen currentpen; path currentpen_path;
+ makelabel(decimal(i),
+ (point .5length(the_edge(i)) of the_edge(i))+
+ 1pt*(udir .5length(the_edge(i)) of the_edge(i)) rotated 90);
+ pickup pencircle scaled 1;
+ draw (point .5length(the_edge(i)) of the_edge(i))--
+ ((point .5length(the_edge(i)) of the_edge(i))+
+ (1pt*(udir .5length(the_edge(i)) of the_edge(i)) rotated 90));
+ makelabel("", point 0 of the_edge(i));
+ fi
+endgroup
+enddef;
+% ---
+def mark_edges =
+ for i_:=-EDGE_.num upto EDGE_.num: if i_<>0: mark_edge(i_); fi endfor
+enddef;
+% ---
+def show_area(expr i) =
+begingroup
+ save j_,v_; j_:=i;
+ message "EDGE " & decimal(j_) & "/" & decimal(EDGE_.pth[j_]) & ":";
+ message "color " &
+ if known EDGE_.col[j_]: decimal(EDGE_.col[j_]) else: "???" fi;
+ v_[j_]:=0;
+ forever: j_:=EDGE_.out[j_]; exitif (j_=i) or (known v_.emerg);
+ if known v_[j_]: v_.emerg:=0; fi
+ v_[j_]:=0; message " " & decimal(j_) & "/" & decimal(EDGE_.pth[j_]);
+ endfor
+endgroup
+enddef;
+% ---
+def show_areas =
+ for i_:=-EDGE_.num upto EDGE_.num: if i_<>0: show_area(i_); fi endfor
+enddef;
+% ---
+def err_helpless =
+ errhelp "Better stop now! Algorithm failed.";
+enddef;
+% ---
+def err_extra_info(expr i,j) =
+ message
+"========================== BEGIN OF ERROR INFO: ==========================";
+ for k_:=i,j:
+ if known k_:
+ message "Edge " & decimal(k_) &
+ " (a subpath of the path " & decimal(EDGE_.pth[k_]) & "):";
+ message "Color:"; show EDGE_.col[k_]; show the_edge(k_);
+ fi
+ endfor;
+enddef;
+% ---
+% principal macros:
+% ---
+vardef edge_path(expr i) = PATH_[EDGE_.pth[i]] enddef;
+vardef first_time(expr i) =
+ TIME_[NODE_.pth[EDGE_.fnd[i]]]tim[NODE_.tim[EDGE_.fnd[i]]]
+enddef;
+vardef last_time(expr i) =
+ TIME_[NODE_.pth[EDGE_.lnd[i]]]tim[NODE_.tim[EDGE_.lnd[i]]]
+enddef;
+% ---
+vardef the_edge(expr i) =
+ if i>0: pos_subpath else: neg_subpath fi
+ (first_time(i), last_time(i)) of edge_path(i)
+enddef;
+% ---
+vardef make_area(expr i) =
+ save j_,q_,v_; path q_; j_:=i; v_[j_]:=0; q_:=the_edge(j_);
+ forever: j_:=EDGE_.out[j_]; exitif (j_=i) or (known v_.emerg);
+ if known v_[j_]:
+ show_area(i); err_helpless;
+ errmessage "RO ERROR: Edge " & decimal(j_) & " revisited";
+ v_.emerg:=0;
+ fi
+ v_[j_]:=0; q_:=q_ && the_edge(j_);
+ endfor
+ make_cycle(q_)
+enddef;
+% ---
+vardef is_tangent(expr i,j,k,l) =
+ save e_,d_,pi_,pj_,ti_,tj_; path e_,pi_,pj_;
+ if (TIME_[i]num=0) or (TIME_[j]num=0): true
+ else:
+ ti_.loc:=TIME_[i]tim[k];
+ ti_.prv:=TIME_[i]tim[(k-1) mod (TIME_[i]num+1)];
+ ti_.nxt:=TIME_[i]tim[(k+1) mod (TIME_[i]num+1)];
+ tj_.loc:=TIME_[j]tim[l];
+ tj_.prv:=TIME_[j]tim[(l-1) mod (TIME_[j]num+1)];
+ tj_.nxt:=TIME_[j]tim[(l+1) mod (TIME_[j]num+1)];
+ pi_:=PATH_[i] shifted (-point ti_.loc of PATH_[i]);
+ pj_:=PATH_[j] shifted (-point tj_.loc of PATH_[j]);
+ d_:=min(
+ distance(point ti_.loc of pi_, point ti_.prv of pi_),
+ distance(point ti_.loc of pi_, point ti_.nxt of pi_),
+ distance(point tj_.loc of pj_, point tj_.prv of pj_),
+ distance(point tj_.loc of pj_, point tj_.nxt of pj_));
+% BUG TRAP 1:
+ if d_<epsil.dist:
+ err_helpless;
+ errmessage "RO ERROR: Cannot check tangency (too short secants)";
+ fi
+ e_:=enc.pth scaled (1/2[epsil.dist,d_]);
+ save ta_,tb_,tc_,td_;
+ save tt_;
+ (tt_,ta_)=(pos_subpath (ti_.prv,ti_.loc) of pi_) intersectiontimes e_;
+ save tt_;
+ (tt_,tb_)=(pos_subpath (ti_.loc,ti_.nxt) of pi_) intersectiontimes e_;
+ save tt_;
+ (tt_,tc_)=(pos_subpath (tj_.prv,tj_.loc) of pj_) intersectiontimes e_;
+ save tt_;
+ (tt_,td_)=(pos_subpath (tj_.loc,tj_.nxt) of pj_) intersectiontimes e_;
+% BUG TRAP 2:
+ if (ta_<0) or (tb_<0) or (tc_<0) or (td_<0):
+ err_helpless; errmessage "RO ERROR: Cannot check tangency";
+ fi
+ forsuffixes tt_:=tb_,tc_,td_: tt_:=(tt_-ta_) mod enc.len; endfor
+ ((tc_>=tb_) and (td_>=tb_)) or ((tc_<=tb_) and (td_<=tb_))
+ fi
+enddef;
+% ---
+vardef multi_path_case = PATH_.num>1 enddef;
+def prepare_input_data(text P)(text W) =
+% |P|: list of paths to be processed (non-cyclic paths are ignored);
+% |W|: list of weights given as pairs: (index, value)
+ PATH_.num:=0;
+ for P_:=P: if cycle P_: PATH_[incr PATH_.num]:=touch_path(P_); fi endfor
+ for W_:=W: PATH_.wei[xpart W_]:=ypart W_; endfor
+ for i_:=1 upto PATH_.num:
+ if unknown PATH_.wei[i_]: PATH_.wei[i_]:=1; fi
+ endfor
+enddef;
+% ---
+def initialise_removing_overlaps =
+% Given paths are |PATH_1|, |PATH_2|, ..., |PATH_[P.num]|;
+% if |PATH_[i][j]| is known, paths |PATH_[i]| and |PATH_[j]| at least touch
+% each other; |PATH_.wei[i]| is a weight of a path (corresponds to
+% multiplying a turning number by this value or, in other words, to
+% applying |PATH_.wei[i]| times a fill operation to the path |PATH_[i]|).
+numeric PATH_.num, PATH_[\\][\\], PATH_.wei[\\]; path PATH_[\\];
+%
+% Lone paths are stored in variable |LONE_|; |LONE_.col[i]| determines
+% the color (being an integer number) of the plane surrounding the path
+% |LONE_[i]|; |LONE_.wei| is a weight inherited from |PATH_.wei| (see above).
+numeric LONE_.num, LONE_.col[\\], LONE_.wei[\\]; path LONE_[\\];
+%
+% |TIME_[i]num| is the number of intersection points for paths |PATH_[i]|,
+% |TIME_[i]tim[j]| is the time of intersection of the |j|-th point of path
+% |PATH_[i]| (points are sorted with respect to time), |TIME_[i]ntp[j]|
+% marks non-tangent points (if known), |TIME_[i]nod[j]| is the node number
+% of |j|-th point of path |PATH_[i]| (only non-tangent points are considered
+% to be nodes, points on a path are numbered from |0|).
+numeric TIME_[\\]num, TIME_[\\]tim[\\], TIME_[\\]ntp[\\], TIME_[\\]nod[\\];
+%
+% Variables with prefix |EDGE_| describe the edge structure that results from
+% intersecting process; the data structure is similar to Dijkstra's data
+% structure for the algorithm finding the convex hull of for a given
+% set of points (E. W. Dijkstra, ``A Discipline of programming'',
+% Prentice-Hall, Inc., 1976): the edges (edsges?) are numbered
+% |-EDGE_.num|, |-EDGE_.num+1|, ..., |-1|, |1|, ... |EDGE_.num-1|,
+% |EDGE_.num|; edges |i| and |-i| are in fact the same edge but
+% differently oriented, the positive value denotes the edge which
+% direction is consistent with the direction of the original path;
+% |EDGE_.out[i]| is the number of the leftmost edge outcoming from
+% the last node, i.e., |EDGE_.lnd[i]|; the number of the first node
+% of |i|-th edge is |EDGE_.fnd[i]|; color of |i|-th edge, i.e., the color
+% of the area surrounded by the edge and its leftmost successors is stored
+% in |EDGE_.col[i]|; |i|-th edge belongs to the path of |PATH_[EDGE_.pth[i]]|;
+% |EDGE_.aux[\\]| is an auxiliary variable; all intersecting paths
+% can be grouped into |SPOT_.num| of disjoint ``spots''; for |i=1|, |2|, ...,
+% |SPOT_.num|, |EDGE_.bed[i]| is the number of the edge which leftmost
+% successors form the area being a boundary of the intersecting paths
+% for a given spot and |EDGE_.bpa[i]| is the boundary (since there is
+% one-to-one correspondence between boundaries and spots, boundaries are
+% pairwise disjoint, too).
+numeric EDGE_.num, EDGE_.pth[\\], EDGE_.out[\\], EDGE_.aux[\\], EDGE_.col[\\],
+ EDGE_.fnd[\\], EDGE_.lnd[\\], EDGE_.are[\\], EDGE_.bed[\\];
+path EDGE_.bpa[\\];
+%
+% Variables with prefix |NODE_| describe the node structure and are related
+% to the edge structure; the node is not a point on a plane but a point on a
+% path, hence several nodes may correspond to one Euclidian point;
+% |NODE_.num| is the number of nodes, |NODE_.pth[i]| is the number of a path
+% to which the node |i| belongs, |NODE_.tim[i]| is the corresponding time on
+% path |PATH_[NODE_.pth[i]]|, |NODE_.ped[i]| is the ordering number of a
+% positively-numbered edge leaving the node |i|, |NODE_.ned[i]| is the
+% ordering number of negatitively-numbered edge leaving node |i|,
+% |NODE_.nod[i]num| is the number of nodes coinciding with node |i| and
+% these are nodes |NODE_.nod[i]1|, |NODE_.nod[i]2|, ...,
+% |NODE_.nod[i][NODE_.nod[i]num]|.
+numeric NODE_.num, NODE_.pth[\\], NODE_.tim[\\], NODE_.ned[\\],
+ NODE_.ped[\\], NODE_.nod[\\]num, NODE_.nod[\\][\\];
+%
+% It often happens that intersecting paths form disjoint areas or that
+% there are paths that do not intersect; it is crucial for the colouring
+% algorithm to know the embedding ``hierarchy''; the hierarchy is stored in
+% a tree structure: the links (suffix |emb|) point upward (from leaves to
+% the root), moreover, with each leaf (node) is associated a ``level,''
+% i.e., the number of leaves beneath this leaf; the information stored in
+% a leaf is either the number of a lone path or the number of an area being
+% the result of the intersecting process (negative value marks the former
+% case); the tree is built by adding at first lone paths and next boundary
+% paths, i.e., negatively oriented paths surrounding groups of paths (areas,
+% see below) resulting from the intersecting process; if there is a lone path
+% or a boundary path |q| embedded in a boundary path |p|, there must be also
+% an area which belongs to the group of areas surrounded by |p|, which apears
+% in the tree between |q| and |p|; such a structure is convenient at the
+% stage of finding colors of areas and lone paths.
+numeric TREE_.num,TREE_.pth[\\],TREE_.emb[\\],TREE_.lev[\\];
+%
+% Finally there are areas which arise during intersecting process;
+% |AREA_1|, |AREA_2|, ..., |AREA_[AREA_.num]| are the ordering numbers
+% of edges which leftmost successors form areas such that areas arising
+% from |AREA_[i]| and |AREA_[j]| are either disjoint or have at most a common
+% edge, and, moreover, areas arising from |AREA_1|, |AREA_2|, ...,
+% |AREA_[AREA_.num]| exhaust the list of all possible areas in question
+% (plus lone paths, i.e., with no intersecting points); |AREA_.spt[i]| is
+% a spot number (areas of the same spot number are subsets of the same
+% boundary, different boundaries are disjoint); areas are sorted wrt spot
+% numbers, moreover, |AREA_[SPOT_[s-1]+1]| thru |AREA_[SPOT_[s]]| are areas
+% belonging to a spot |s|, |s=1|, |2|, ..., |SPOT_.num|.
+numeric AREA_.num, AREA_[\\], AREA_.spt[\\]; numeric SPOT_.num, SPOT_[\\];
+enddef;
+% ---
+vardef is_far_enough(expr i,k,dk) =
+ if act_idx_>=max_idx: were_more_:=1; false
+ else:
+ save z_; pair z_; z_:=point k+dk of PATH_[i];
+ true
+ for j_:=0 upto TIME_[i]num:
+ and
+ if multi_path_case:
+ (distance(point TIME_[i]tim[j_] of PATH_[i],z_)>=epsil.dist)
+ else:
+ (interval(TIME_[i]tim[j_],(k+dk),PATH_[i])>=epsil.time)
+ fi
+ endfor
+ for j_:=0 upto ignored_.num:
+ and
+ if multi_path_case:
+ (distance(point ignored_[j_] of PATH_[i],z_)>=epsil.dist)
+ else:
+ (interval(ignored_[j_],(k+dk),PATH_[i])>=epsil.time)
+ fi
+ endfor
+ fi
+enddef;
+% ---
+def intersect_two_segments(expr i,j,k,l) =
+begingroup
+ save pi_,pj_,stack_; path pi_,pj_,stack_[\\]; numeric stack_.lev;
+ pi_:=subpath (k,k+1) of PATH_[i]; pj_:=subpath (l,l+1) of PATH_[j];
+ stack_.lev:=1; stack_[stack_.lev]:=pj_;
+ forever:
+ exitif stack_.lev<=0;
+ pj_:=stack_[stack_.lev]; stack_.lev:=stack_.lev-1;
+ save dk_,dl_; (dk_,dl_)=pi_ intersectiontimes pj_;
+ if dk_>=0:
+ if is_far_enough(i,k,dk_):
+ act_idx_:=act_idx_+1; TIME_[i].tim[incr TIME_[i].num]:=k+dk_;
+ else: ignored_[incr ignored_.num]:=k+dk_;
+ fi
+ if (dl_+epsil.time)<length(pj_):
+ stack_[incr stack_.lev]:=subpath (dl_+epsil.time,length pj_) of pj_;
+ fi
+ if (dl_-epsil.time)>0:
+ stack_[incr stack_.lev]:=subpath (0,dl_-epsil.time) of pj_;
+ fi
+ fi
+ endfor
+endgroup
+enddef;
+% ---
+def intersect_two_paths(expr i,j) =
+begingroup
+ save ignored_,were_more_,act_idx_;
+ act_idx_:=0; ignored_.num:=-1;
+ for k_:=0 upto length(PATH_[i])-1:
+ for l_:=0 upto length(PATH_[j])-1:
+ if (i<>j) or (k_<>l_):
+ intersect_two_segments(i,j,k_,l_);
+ fi
+ endfor
+ endfor
+ if known were_more_:
+ errhelp "Dangerous situation: rounding errors may screw up results.";
+ errmessage "RO ERROR: there were more than "
+ & decimal(max_idx) & " intersections (thus some were ignored)";
+ fi
+ quicksort TIME_[i](0,TIME_[i].num)(tim)();
+endgroup
+enddef;
+% ---
+def intersect_all_paths =
+ for i_:=1 upto PATH_.num: TIME_[i_]num:=-1; endfor
+ for i_:=1 upto PATH_.num:
+ for j_:=i_+1 upto PATH_.num:
+ if xpart(PATH_[i_] intersectiontimes PATH_[j_])>-1:
+ PATH_[i_][j_]:=0;
+% the process is repeated twice (for both paths in turn) because we haven't
+% invented an efficient soultion to the following problem:
+% given a subpath |S| of a path |P| and a time |t.S|; find a time |t.P| such
+% that |point t.S of S=point t.P of P|
+ intersect_two_paths(i_,j_); intersect_two_paths(j_,i_);
+ fi
+ endfor
+ endfor
+ if not multi_path_case:
+ for i_:=1 upto PATH_.num:
+ PATH_[i_][i_]:=0; intersect_two_paths(i_,i_);
+ endfor
+ fi
+enddef;
+% ---
+vardef find_minimal_secant =
+ save secants_, intervals_;
+ secants_.num:=0; intervals_.num:=0;
+ minimal_secant:=minimal_interval:=infinity;
+ for i_:=1 upto PATH_.num:
+ for j_:=0 upto TIME_[i_].num:
+ if TIME_[i_].num>0:
+ secants_[if tracingremoving>1: incr fi \\ secants_.num]:=
+ distance(point TIME_[i_]tim[j_] of PATH_[i_],
+ point TIME_[i_]tim[(j_+1) mod (TIME_[i_].num+1)] of PATH_[i_]);
+ if tracingremoving>1:
+ secants_.pth[secants_.num]:=i_; secants_.tim[secants_.num]:=j_;
+ fi
+ minimal_secant:=min(minimal_secant,secants_[secants_.num]);
+ intervals_[if tracingremoving>1: incr fi \\ intervals_.num]:=
+ interval(TIME_[i_]tim[j_],
+ TIME_[i_]tim[(j_+1) mod (TIME_[i_].num+1)], PATH_[i_]);
+ if tracingremoving>1:
+ intervals_.pth[intervals_.num]:=i_; intervals_.tim[intervals_.num]:=j_;
+ fi
+ minimal_interval:=min(minimal_interval,intervals_[intervals_.num]);
+ fi
+ endfor;
+ endfor;
+ if minimal_secant<>infinity:
+ info_ro "Minimal secant = " & decimal(minimal_secant/pt)
+ & "pt, i.e., " & decimal(minimal_secant) & "pxl, " &
+ if minimal_secant<4/3epsil.dist: "CAVEAT!" else: "seems OK" fi
+ & " (bound=" & decimal(epsil.dist) & "pxl)";
+ fi
+ if minimal_interval<>infinity:
+ info_ro "Minimal interval = " & decimal(minimal_interval) & ", " &
+ if minimal_interval<4/3epsil.time: "CAVEAT!" else: "seems OK" fi
+ & " (bound=" & decimal(epsil.time) & ")";
+ fi
+ if tracingremoving>1:
+ quicksort secants_(1,secants_.num)()(tim,pth);
+ quicksort intervals_(1,intervals_.num)()(tim,pth);
+ for i_:=1 upto secants_.num:
+ info_ro "secant=" & decimal(secants_[i_])
+ & " path=" & decimal(secants_.pth[i_])
+ & " time=" & decimal(secants_.tim[i_]);
+ endfor
+ for i_:=1 upto intervals_.num:
+ info_ro "interval=" & decimal(intervals_[i_])
+ & " path=" & decimal(intervals_.pth[i_])
+ & " time=" & decimal(intervals_.tim[i_]);
+ endfor
+ fi
+enddef;
+% ---
+def build_node_structure =
+begingroup
+ save n_,Tik_,Tjl_;
+ NODE_.num:=0;
+ for i_:=1 upto PATH_.num:
+ for j_:=i_ if multi_path_case: +1 fi upto PATH_.num:
+ if known PATH_[i_][j_]:
+ for k_:=0 upto TIME_[i_]num:
+ for l_:=if i_=j_: k_ else: 0 fi upto TIME_[j_]num:
+ if distance(point TIME_[i_]tim[k_] of PATH_[i_],
+ point TIME_[j_]tim[l_] of PATH_[j_])<epsil.dist:
+ if if multi_path_case: not is_tangent(i_,j_,k_,l_) else: true fi:
+ TIME_[i_]ntp[k_]:=1; TIME_[j_]ntp[l_]:=1;
+ if unknown TIME_[i_]nod[k_]:
+ NODE_.num:=NODE_.num+1; TIME_[i_]nod[k_]:=NODE_.num;
+ NODE_.pth[NODE_.num]:=i_; NODE_.tim[NODE_.num]:=k_;
+ NODE_.nod[NODE_.num]num:=0;
+ fi
+ if unknown TIME_[j_]nod[l_]:
+ NODE_.num:=NODE_.num+1; TIME_[j_]nod[l_]:=NODE_.num;
+ NODE_.pth[NODE_.num]:=j_; NODE_.tim[NODE_.num]:=l_;
+ NODE_.nod[NODE_.num]num:=0;
+ fi
+ Tik_:=TIME_[i_]nod[k_]; Tjl_:=TIME_[j_]nod[l_];
+ NODE_.nod[Tik_][incr NODE_.nod[Tik_]num]:=Tjl_;
+ if (i_<>j_) or (k_<>l_):
+ NODE_.nod[Tjl_][incr NODE_.nod[Tjl_]num]:=Tik_;
+ fi
+ fi
+ fi
+ endfor
+ endfor
+ fi
+ endfor
+ endfor
+% BUG TRAP:
+ for i_:=1 upto PATH_.num:
+ n_:=0;
+ for j_:=0 upto TIME_[i_]num: if known TIME_[i_]ntp[j_]: n_:=n_+1; fi endfor
+ if n_=1:
+ err_helpless;
+ errmessage "RO ERROR: Number of non-tangent points must not be 1 (path "
+ & decimal(i_) & ")";
+ fi
+ endfor
+endgroup
+enddef;
+% ---
+def identify_close_nodes =
+begingroup
+% It is assumed that `close points' and `coinciding points' means the same,
+% hence we make a transitive closure of the relation of `being close'
+% (in ``normal'' cases the relation is transitive, although from
+% a mathematical point of view it is obviously not):
+ forever:
+ % Is this loop really needed? I (BJ) could not devise a case where
+ % more than two turns would be necessary and where the algorithm
+ % would still work properly
+ save changed_;
+ for i_:=1 upto NODE_.num:
+ save v_;
+ for j_:=1 upto NODE_.nod[i_]num: v_[NODE_.nod[i_][j_]]:=0; endfor
+ for j_:=1 upto NODE_.nod[i_]num:
+ k_:=NODE_.nod[i_][j_];
+ for l_:=1 upto NODE_.nod[k_]num:
+ if NODE_.nod[k_][l_]<>i_:
+ if unknown v_[NODE_.nod[k_][l_]]:
+ NODE_.nod[i_][incr NODE_.nod[i_]num]:=NODE_.nod[k_][l_];
+ changed_:=v_[NODE_.nod[k_][l_]]:=0;
+ fi
+ fi
+ endfor
+ endfor
+ endfor
+ exitif unknown changed_;
+ endfor
+endgroup
+enddef;
+% ---
+def build_edge_structure =
+begingroup
+ numeric min_sec_[\\],min_sec_.tmp;
+% |min_sec_[i]| is a minimal secant for |i|-th path, |i=1|, |2|, ..., |PATH_.num|
+ save i_,j_,k_;
+ EDGE_.num:=0;
+ if NODE_.num>0:
+ for i_:=1 upto PATH_.num:
+ for j_:=0 upto TIME_[i_]num:
+ if known TIME_[i_]ntp[j_]:
+ EDGE_.num:=EDGE_.num+1; EDGE_.pth[EDGE_.num]=i_;
+ EDGE_.pth[-EDGE_.num]=i_; EDGE_.fnd[EDGE_.num]:=TIME_[i_]nod[j_];
+% each path should contain at least two non-tangent nodes
+ k_:=j_+1;
+ forever: exitif known TIME_[i_]ntp[k_ mod (TIME_[i_]num+1)];
+ k_:=k_+1;
+ endfor;
+ EDGE_.lnd[EDGE_.num]:=TIME_[i_]nod[k_ mod (TIME_[i_]num+1)];
+ min_sec_.tmp:=
+ distance(point first_time(EDGE_.num) of edge_path(EDGE_.num),
+ point last_time(EDGE_.num) of edge_path(EDGE_.num));
+ if if unknown min_sec_[i_]: true else: min_sec_[i_]>min_sec_.tmp fi:
+ min_sec_[i_]:=min_sec_.tmp;
+ fi
+ EDGE_.fnd[-EDGE_.num]:=EDGE_.lnd[EDGE_.num];
+ EDGE_.lnd[-EDGE_.num]:=EDGE_.fnd[EDGE_.num];
+ fi
+ endfor
+ endfor
+ for i_:=-EDGE_.num upto EDGE_.num:
+ if i_>0: NODE_.ped[EDGE_.fnd[i_]]:=i_;
+ elseif i_<0: NODE_.ned[EDGE_.fnd[i_]]:=i_;
+ fi
+ endfor
+ else:
+ info_ro "RO WARNING: no intersections detected.";
+ fi
+endgroup
+enddef;
+% ---
+def find_leftmost_edges =
+% a simple method is used: a tiny circle is drawn in a node and its
+% intersection points with all edges leaving the node are examined
+begingroup
+ save ei_,ej_,i_,j_,k_,leftmost_; path ei_,ej_; numeric min_sec_.loc;
+ for i_:=-EDGE_.num upto EDGE_.num: if i_<>0:
+ if tracingleftmost>0:
+ message "@@@ " & decimal(i_) & "/" & decimal(EDGE_.pth[i_])
+ & " (" & decimal(EDGE_.fnd[i_]) & "," & decimal(EDGE_.lnd[i_]) & "):";
+ fi
+ numeric leftmost_.edg,leftmost_.tim,leftmost_.tmp;
+ min_sec_.loc:=min_sec_[EDGE_.pth[i_]];
+ for k_:=1 upto NODE_.nod[EDGE_.lnd[i_]]num:
+ forsuffixes $:=ped,ned:
+ j_:=NODE_$[NODE_.nod[EDGE_.lnd[i_]][k_]];
+ min_sec_.loc:=min(min_sec_.loc,min_sec_[EDGE_.pth[j_]]);
+ endfor
+ endfor
+% BUG TRAP 1: (should not happen, see |find_minimal_secant|);
+ if min_sec_.loc<epsil.dist:
+ err_extra_info(i_,whatever); showvariable min_sec_; err_helpless;
+ errmessage "RO ERROR: Cannot continue searching for the leftmost edge";
+ fi
+ ei_:=enc.pth scaled (1/2[epsil.dist,min_sec_.loc])
+ shifted point infinity of the_edge(i_);
+ save tei_,tt_; (tei_,tt_)=ei_ intersectiontimes the_edge(i_);
+ for k_:=1 upto NODE_.nod[EDGE_.lnd[i_]]num:
+ forsuffixes $:=ped,ned:
+ j_:=NODE_$[NODE_.nod[EDGE_.lnd[i_]][k_]];
+ ej_:=enc.pth scaled (1/2[epsil.dist,min_sec_.loc])
+ shifted point 0 of the_edge(j_);
+ if tracingleftmost>0:
+ message " " & decimal(j_) & "/" & decimal(EDGE_.pth[j_])
+ & " (" & decimal(EDGE_.fnd[j_]) & "," & decimal(EDGE_.lnd[j_]) & "):";
+ fi
+ save tej_,tt_; (tej_,tt_)=ej_ intersectiontimes the_edge(j_);
+% BUG TRAP 2:
+ if (tei_<0) or (tej_<0):
+ err_extra_info(i_,j_); showvariable min_sec_;
+ message "Times: " & decimal(tei_) & " " & decimal(tej_);
+ err_helpless;
+ errmessage "RO ERROR: Unsuccesful search for the leftmost edge";
+ fi
+% it happens that |i_=j_| if |multi_path_case=false|
+ leftmost_.tmp:=if (i_=-j_): 0 else: (tej_-tei_) mod enc.len fi;
+ if tracingleftmost>0:
+ message " " & decimal(leftmost_.tmp) & " " & dec_pair((tei_,tej_));
+ fi
+ if if unknown leftmost_.tim: true else: leftmost_.tmp>leftmost_.tim fi:
+ leftmost_.edg:=j_; leftmost_.tim:=leftmost_.tmp;
+ fi
+ endfor
+ endfor
+ EDGE_.out[i_]:=leftmost_.edg;
+ if tracingleftmost>0: j_:=EDGE_.out[i_];
+ message ">>> " & decimal(j_) & "/" & decimal(EDGE_.pth[j_])
+ & " (" & decimal(EDGE_.fnd[j_]) & "," & decimal(EDGE_.lnd[j_]) & "):";
+ fi
+ fi endfor
+endgroup
+enddef;
+% ---
+def build_area_structure =
+begingroup
+ save i_,j_,v_;
+ AREA_.num:=0;
+ for i_:=1 upto EDGE_.num: % \MF's linear equation solver employed
+ EDGE_.col[i_]-PATH_.wei[EDGE_.pth[i_]]=EDGE_.col[-i_];
+ endfor
+% split to areas (edges surrounding the same area are assigned the same colour):
+ for i_:=-EDGE_.num upto EDGE_.num:
+ if (i_<>0) and (unknown EDGE_.are[i_]):
+ AREA_[incr AREA_.num]:=i_;
+ save v_; j_:=i_; v_[j_]:=0; EDGE_.are[j_]:=AREA_.num;
+ forever: j_:=EDGE_.out[j_]; exitif (j_=i_) or (known v_.emerg);
+% BUG TRAP 1:
+ if j_=-i_:
+ err_extra_info(i_,whatever); show_area(i_); err_helpless;
+ errmessage "RO ERROR: strange area";
+ fi
+% BUG TRAP 2:
+ if known v_[j_]:
+ err_extra_info(i_,j_); show_area(i_); err_helpless;
+ errmessage "RO ERROR: Edge " & decimal(j_) & " revisited";
+ v_.emerg:=0;
+ fi
+ v_[j_]:=0; EDGE_.are[j_]:=AREA_.num;
+ if known (EDGE_.col[i_]-EDGE_.col[j_]):
+% BUG TRAP 3:
+ if (EDGE_.col[i_]-EDGE_.col[j_])<>0:
+ err_extra_info(i_,j_); show_area(i_); err_helpless;
+ errmessage "RO ERROR: Edges " & decimal(i_) & " and " & decimal(j_)
+ & " have inconsistent colors";
+ fi
+ else: EDGE_.col[i_]=EDGE_.col[j_]; fi
+ endfor
+ fi
+ endfor
+endgroup
+enddef;
+% ---
+def build_spot_structure =
+begingroup
+ save i_,j_;
+% areas having a common edge belong to the same spot (\MF's linear
+% equation solver employed):
+ for i_:=1 upto EDGE_.num: if (i_<>0):
+ if unknown (AREA_.spt[EDGE_.are[i_]]-AREA_.spt[EDGE_.are[-i_]]):
+ AREA_.spt[EDGE_.are[i_]]=AREA_.spt[EDGE_.are[-i_]];
+ fi
+ fi endfor
+% count different spots:
+ SPOT_.num:=0;
+ for i_:=1 upto AREA_.num:
+ if unknown AREA_.spt[i_]: AREA_.spt[i_]=incr SPOT_.num; fi
+ endfor;
+% sort areas wrt spot numbers:
+ quicksort AREA_(1,AREA_.num)(spt)();
+% define |SPOT_[s]|, |s=1|, |2|, ..., |SPOT_.num|, such that
+% |AREA_[SPOT_[s-1]+1]| thru |AREA_[SPOT_[s]]| are areas having the
+% same spot number |s|:
+ SPOT_0=0; for i_:=1 upto AREA_.num: SPOT_[AREA_.spt[i_]]:=i_; endfor
+% identify paths for which |check_turn=-1| (such areas are boundaries and
+% should be unique for each spot):
+ i_:=0;
+ for j_:=1 upto AREA_.num:
+ if check_turn(make_area(AREA_[j_]))<=0:
+ i_:=i_+1;
+ EDGE_.bar[i_]:=j_; EDGE_.bed[i_]:=AREA_[j_];
+ EDGE_.bpa[i_]:=make_area(AREA_[j_]);
+ fi
+ endfor
+% BUG TRAP 4:
+ if i_<>SPOT_.num:
+ message "Number of spots=" & decimal(SPOT_.num) &
+ ", number of boundaries=" & decimal(i_);
+ err_helpless;
+ errmessage "RO ERROR: Inconsistent number of spots and boundaries";
+ fi
+endgroup
+enddef;
+% ---
+def update_tree_levels(expr n) =
+% update levels above the inserted leaf (|n|):
+begingroup
+ save i_,j_;
+ i_:=TREE_.emb[n]; j_:=TREE_.lev[n];
+ forever:
+ exitif i_=0;
+ j_:=TREE_.lev[i_]:=max(j_+1,TREE_.lev[i_]); i_:=TREE_.emb[i_];
+ endfor
+endgroup
+enddef;
+% ---
+vardef embedding_pair(expr p,n) =
+% returns a pair of numbers, |(out_,in_)|, such that |out_| is either a tree
+% address of an area surrounded |p| or zero if not found, and |in_| is a
+% tree address of an area surrounding |p| or zero if not found; one branch
+% is searched, starting from a zero level leaf, |n|.
+ save in_,out_,q_; path q_; in_:=out_:=0; n_:=n;
+ forever:
+ q_:=if TREE_.pth[n_]<0: LONE_[-TREE_.pth[n_]]
+ else: make_area(AREA_[TREE_.pth[n_]]) fi;
+ check_embedding(p_,q_,r_);
+ if r_=1: % |p_| $\subset$ |q_|
+ if in_=0: in_:=n_; fi % ``minimal'' surrounding path is to be found
+ elseif r_=2: % |q_| $\subset$ |p_|
+ out_:=n_; % ``maximal'' surrounded path is to be found
+ fi
+ exitif TREE_.emb[n_]=0;
+ n_:=TREE_.emb[n_];
+ endfor
+ (out_,in_)
+enddef;
+% ---
+def add_to_queue (expr p,q) =
+% updates a queue, i.e., adds to a queue an area belonging to the spot
+% of a boundary area, i.e., |AREA_[q]|, surrounding a path described by
+% a tree address |p|.
+begingroup
+ save p_,r_,s_,found_; path p_; boolean found_;
+% |AREA_[q]| is a boundary, i.e., it is negatively oriented,
+ p_:=if TREE_.pth[p]<0: LONE_[-TREE_.pth[p]]
+ else: make_area(AREA_[TREE_.pth[p]]) fi;
+% there must be a unique positively oriented area containing |p_|, belonging
+% to the ``spot'' of the boundary |AREA_[q]|.
+ found_:=false; s_:=SPOT_[AREA_.spt[q]-1];
+% |s_| is the last area from a previous spot, |s_+1| will be the first
+% area of the current spot
+ forever: s_:=s_+1;
+ if s_<>q:
+ check_embedding(make_area(AREA_[s_]),p_,r_);
+ found_:=(r_=2); % |r_=2| implies |p_| $\subset$ |make_area(AREA_[s_])|
+ fi
+ if found_:
+ if unknown LVQ_.inq[s_]: LVQ_[incr LVQ_.num]:=s_; LVQ_.inq[s_]:=1; fi
+ elseif s_=SPOT_[AREA_.spt[q]]:
+% the list of candidates has been exhausted without a success, hence
+% BUG TRAP:
+ err_helpless;
+ errmessage "RO ERROR: cannot build embedding tree (boundary " &
+ decimal(q) & ")";
+ found_:=true;
+ fi
+ exitif found_;
+ endfor;
+endgroup
+enddef;
+% ---
+def add_to_tree (expr leaf) =
+begingroup
+ save boundary_,found_,N_,p_; path p_;
+ TREE_.num:=TREE_.num+1;
+ N_:=TREE_.num; % abbreviation
+ TREE_.pth[N_]:=leaf; TREE_.emb[N_]:=0; TREE_.lev[N_]:=0;
+ p_:=if leaf<0: LONE_[-leaf] else: make_area(AREA_[leaf]) fi;
+ if (leaf>0) and (check_turn(p_)<0): boundary_:=1; fi
+ if N_>1:
+ for l_:=1 upto LVZ_.num: % climbing up from level zero
+ save out_,in_; (out_,in_)=embedding_pair(p_,LVZ_[l_]);
+ if (out_<>0) or (in_<>0): % a feasible branch found
+ if (out_=0) and (in_<>0): % to be added at the bottom, certain
+ TREE_.emb[N_]:=in_;
+ if in_=LVZ_[l_]: LVZ_[l_]:=N_; % replace bottom leaf
+ else: LVZ_[incr LVZ_.num]:=N_; fi % add new bottom leaf
+ elseif (out_<>0) and (in_=0): % to be added at the top, optional
+ if TREE_.emb[out_]<>N_: % we weren't here, add
+% invariant: |TREE_.emb[out_]=0|
+ TREE_.emb[out_]:=N_;
+ TREE_.lev[N_]:=max(TREE_.lev[N_],TREE_.lev[out_]+1);
+ if known boundary_: add_to_queue(out_,leaf); fi
+ fi
+ else: % to be added in the midst, optional
+ if TREE_.emb[out_]<>N_: % we weren't here, add
+% invariant: |TREE_.emb[out_]=in_|
+ TREE_.emb[out_]:=N_; TREE_.emb[N_]:=in_;
+ TREE_.lev[N_]:=max(TREE_.lev[N_],TREE_.lev[out_]+1);
+ if known boundary_: add_to_queue(out_,leaf); fi
+ fi
+ fi
+ found_:=1; update_tree_levels(N_);
+ fi
+ endfor;
+ fi
+ if unknown found_: LVZ_[incr LVZ_.num]:=N_; fi % a ``separate'' leaf appeared
+endgroup
+enddef;
+% ---
+def build_embedding_tree =
+begingroup
+ save LVZ_,QUE_;
+% |LVZ_1|, |LVZ_2|, ..., |LVZ_[LVZ_.num]| is the list of zero-level leaves,
+% (a temporary data structure, used during building a tree), |LVQ_1|, |LVQ_2|,
+% ..., |LVQ_[LVQ_.num]| is the list of leaves waiting in a queue (also
+% a temporary data structure); if |LVQ_.inq[i]| is known, |i=1|, |2|, ...,
+% |AREA_.num|, area |i| is already in a queue.
+ TREE_.num:=0; LONE_.num:=0; LVZ_.num:=0; LVQ_.num:=0;
+% identify lone paths:
+ for i_:=1 upto PATH_.num:
+ if true for j_:=0 upto TIME_[i_]num: and (unknown TIME_[i_]ntp[j_]) endfor:
+ LONE_[incr LONE_.num]:=PATH_[i_]; LONE_.wei[LONE_.num]:=PATH_.wei[i_];
+ fi
+ endfor
+% build the tree:
+ for i_:=1 upto LONE_.num: add_to_tree(-i_); endfor
+ for i_:=1 upto SPOT_.num: add_to_tree(EDGE_.bar[i_]); endfor
+ for i_:=1 upto LVQ_.num: add_to_tree(LVQ_[i_]); endfor
+endgroup
+enddef;
+% ---
+def color_paths = % \MF's linear equation solver heavily exploited
+begingroup
+ save i_,j_;
+ for i_:=1 upto TREE_.num:
+ if TREE_.emb[i_]=0: % outer path
+ if TREE_.pth[i_]<0: LONE_.col[-TREE_.pth[i_]]=background_color;
+ else: EDGE_.col[AREA_[TREE_.pth[i_]]]=background_color; fi
+ else: % inner path, inherits color from the surrounding path
+ j_:=TREE_.emb[i_];
+ if TREE_.pth[i_]<0:
+ if TREE_.pth[j_]<0:
+ LONE_.col[-TREE_.pth[i_]]=LONE_.col[-TREE_.pth[j_]]
+ +LONE_.wei[-TREE_.pth[j_]]*check_turn(LONE_[-TREE_.pth[j_]]);
+ else:
+ LONE_.col[-TREE_.pth[i_]]=EDGE_.col[AREA_[TREE_.pth[j_]]];
+ fi
+ else:
+ if TREE_.pth[j_]<0:
+ EDGE_.col[AREA_[TREE_.pth[i_]]]=LONE_.col[-TREE_.pth[j_]]
+ +LONE_.wei[-TREE_.pth[j_]]*check_turn(LONE_[-TREE_.pth[j_]]);
+ else:
+ if AREA_.spt[TREE_.pth[i_]]<>AREA_.spt[TREE_.pth[j_]]:
+ EDGE_.col[AREA_[TREE_.pth[i_]]]=EDGE_.col[AREA_[TREE_.pth[j_]]];
+ fi
+ fi
+ fi
+ fi
+ endfor;
+endgroup
+enddef;
+% ---
+def recombine_edges(suffix R) =
+% this routine can be used several times (after completing the process
+% of finding the structure of paths after intersecting) with various
+% definitions of |good_color| function in order to select various
+% sets of areas
+ if not path R0: numeric R.num; path R[\\]; fi
+ if (unknown R.num) or (unknown append_results): R.num:=0; fi
+% |R|: resulting data structure, namely, |R.num| is the number of output
+% paths, |R1|, |R2|, ..., |R[R.num]| are the resulting paths
+begingroup
+ save i_,j_,out_,in_;
+ for i_:=1 upto LONE_.num:
+ out_:=LONE_.col[i_]; in_:=out_+LONE_.wei[i_]*check_turn(LONE_[i_]);
+ if good_colors(in_,out_) or good_colors(out_,in_):
+ R[incr R.num]:=LONE_[i_];
+ R[R.num]:=if good_colors(in_,out_): pos_turn else: neg_turn fi \\ R[R.num];
+ fi
+ endfor
+ for i_:=-EDGE_.num upto EDGE_.num: if i_<>0:
+ EDGE_.aux[i_]:=whatever;
+ fi endfor
+ for i_:=-EDGE_.num upto EDGE_.num: if i_<>0:
+% BUG TRAP 1:
+ if unknown EDGE_.col[i_]:
+ err_extra_info(i_,whatever); err_helpless;
+ errmessage "RO ERROR: Edge " & decimal(j_) & " not colored";
+ fi
+ if good_colors(EDGE_.col[i_],EDGE_.col[-i_]) and (unknown EDGE_.aux[i_]):
+ save v_;
+ R.num:=R.num+1; j_:=i_; v_[j_]:=0;
+ EDGE_.aux[j_]:=0; R[R.num]:=the_edge(j_);
+ forever: j_:=EDGE_.out[j_]; exitif (j_=i_) or (known v_.emerg);
+% BUG TRAP 2:
+ if known v_[j_]:
+ err_extra_info(i_,j_); err_helpless;
+ errmessage "RO ERROR: Edge " & decimal(j_) & " revisited";
+ v_.emerg:=0;
+ fi
+ v_[j_]:=0;
+ if good_colors(EDGE_.col[j_],EDGE_.col[-j_]):
+ EDGE_.aux[j_]:=0; R[R.num]:=R[R.num] && the_edge(j_);
+ else: j_:=-j_;
+ fi
+ endfor
+ R[R.num]:=clean_path(clean_path(make_cycle(R[R.num])));
+ fi
+ fi endfor
+endgroup
+enddef;
+% ---
+def remove_overlap (text P)(text W) suffix R =
+begingroup interim autorounding:=0;
+% |P|: list of paths to be processed (non-cyclic paths are ignored);
+% |W|: list of weights given as pairs: (index, value)
+% |R|: resulting data structure, i.e., |R.num| is the number of output paths,
+% |R1|, |R2|, ..., |R[R.num]| are the resulting paths
+ info_ro "initialise_removing_overlaps"; initialise_removing_overlaps;
+ info_ro "prepare_input_data"; prepare_input_data(P)(W);
+ info_ro "intersect_all_paths"; intersect_all_paths;
+ info_ro "find_minimal_secant"; find_minimal_secant;
+ info_ro "build_node_structure"; build_node_structure;
+ info_ro "identify_close_nodes"; identify_close_nodes;
+ info_ro "build_edge_structure"; build_edge_structure;
+ info_ro "find_leftmost_edges"; find_leftmost_edges;
+ info_ro "build_area_structure"; build_area_structure;
+ info_ro "build_spot_structure"; build_spot_structure;
+ info_ro "build_embedding_tree"; build_embedding_tree;
+ info_ro "color_paths"; color_paths;
+ info_ro "recombine_edges"; recombine_edges(R);
+endgroup
+enddef;
+% ---
+% E-S MACROS:
+% ---
+vardef make_join@#(expr pa,pb)=
+ save kind_; string kind_; kind_:=str @#; if kind_="": kind_:="0" fi;
+ if (kind_<>"0") and (kind_<>"1"):
+ errhelp "Will use default.";
+ errmessage "ES ERROR: don't know how to join";
+ kind_:="0";
+ fi
+ if distance(point length(pa) of pa,point 0 of pb)<epsil.dist:
+ if (point length(pa) of pa)<>(point 0 of pb):
+ info_es "Points " & dec_pair(point length(pa) of pa) &
+ " and " & dec_pair(point 0 of pb) & " joined";
+ if (tracingexpanding>0) and (proofing>0):
+ makelabel.lft.nodot("joined",point length(pa) of pa);
+ fi
+ fi
+ pa && pb
+ elseif kind_="0":
+ if miter_size<=0: % a special case, isn't it?
+ pa--pb
+ else:
+ save ta_,tb_,za_,da_,zb_,db_,zc_,zd_,ze_,zf_;
+ pair za_,da_,zb_,db_,zc_,zd_,ze_,zf_;
+ za_=point length(pa) of pa;
+ da_=direction length(pa) of pa;
+ zb_=point 0 of pb;
+ db_=direction 0 of pb;
+ zc_=whatever[za_,za_+da_]=whatever[ze_,ze_+(zb_-za_)];
+ zd_=whatever[zb_,zb_+db_]=whatever[ze_,ze_+(zb_-za_)];
+ ze_=.5[za_,zb_]+miter_size*(unitvector(da_-db_));
+% we used to check |turningnumber(za_--zc_--zd_--zb_--cycle)|, but it was
+% not sufficiently robust
+ (ta_,tb_)=(za_--zc_) intersectiontimes (zd_--zb_);
+ if ta_<0: % |miter_size| in force:
+ pa
+ if distance(point length(pa) of pa,zc_)>=epsil.dist: --zc_ fi
+ if (distance(zc_,zd_)>=epsil.dist)
+ and (distance(point 0 of pb,zd_)>=epsil.dist): --zd_ fi
+ --pb
+ else:
+ zf_:=point ta_ of (za_--zc_);
+ if abs(zf_-.5[za_,zb_])>abs(ze_-.5[za_,zb_]): % |miter_size| in force:
+ pa
+ if distance(point length(pa) of pa,zc_)>=epsil.dist: --zc_ fi
+ if (distance(zc_,zd_)>=epsil.dist)
+ and (distance(point 0 of pb,zd_)>=epsil.dist): --zd_ fi
+ --pb
+ else:
+ pa
+ if (distance(point length(pa) of pa,zf_)>=epsil.dist)
+ and (distance(point 0 of pb,zf_)>=epsil.dist): --zf_ fi
+ --pb
+ fi
+ fi
+ fi
+ elseif kind_="1":
+ pa{direction length(pa) of pa}..{direction 0 of pb}pb
+ fi
+enddef;
+% ---
+vardef make_cyclic_join@#(expr p)=
+ save kind_; string kind_; kind_:=str @#; if kind_="": kind_:="0" fi;
+ if (kind_<>"0") and (kind_<>"1"):
+ errhelp "Will use default.";
+ errmessage "ES ERROR: don't know how to join";
+ kind_:="0";
+ fi
+ if distance(point length(p) of p,point 0 of p)<epsil.dist:
+ if (point length(p) of p)<>(point 0 of p):
+ info_es "Points " & dec_pair(point length(p) of p) &
+ " and " & dec_pair(point 0 of p) & " joined (cycle)";
+ if (tracingexpanding>0) and (proofing>0):
+ makelabel.lft.nodot("joined (cycle)",point length(p) of p);
+ fi
+ fi
+ make_cycle(p)
+ elseif kind_="0":
+ if miter_size<=0: % a special case, isn't it?
+ p--cycle
+ else:
+ save ta_,tb_,za_,da_,zb_,db_,zc_,zd_,ze_,zf_; pair za_,da_,zb_,db_,zc_,zd_,ze_,zf_;
+ za_=point length(p) of p; da_=direction length(p) of p;
+ zb_=point 0 of p; db_=direction 0 of p;
+ zc_=whatever[za_,za_+da_]=whatever[ze_,ze_+(zb_-za_)];
+ zd_=whatever[zb_,zb_+db_]=whatever[ze_,ze_+(zb_-za_)];
+ ze_=.5[za_,zb_]+miter_size*(unitvector(da_-db_));
+% we used to check |turningnumber(za_--zc_--zd_--zb_--cycle)|, but it was
+% not sufficiently robust
+ (ta_,tb_)=(za_--zc_) intersectiontimes (zd_--zb_);
+ if ta_<0: % |miter_size| in force:
+ p
+ if distance(point length(p) of p,zc_)>=epsil.dist: --zc_ fi
+ if (distance(zc_,zd_)>=epsil.dist)
+ and (length((point 0 of p)-zd_)>=epsil.dist): --zd_ fi
+ --cycle
+ else:
+ zf_:=point ta_ of (za_--zc_);
+ if abs(zf_-.5[za_,zb_])>abs(ze_-.5[za_,zb_]): % |miter_size| in force:
+ p
+ if distance(point length(p) of p,zc_)>=epsil.dist: --zc_ fi
+ if (distance(zc_,zd_)>=epsil.dist)
+ and (distance(point 0 of p,zd_)>=epsil.dist): --zd_ fi
+ --cycle
+ else:
+ p
+ if (distance(point length(p) of p,zf_)>=epsil.dist)
+ and (distance(point 0 of p,zf_)>=epsil.dist): --zf_ fi
+ --cycle
+ fi
+ fi
+ fi
+ elseif kind_="1":
+ p{direction length(p) of p}..{direction 0 of p}cycle
+ fi
+enddef;
+% ---
+vardef make_end@#(expr pr,pl) =
+ save kind_; string kind_; kind_:=str @#; if kind_="": kind_:="0" fi;
+ if (kind_<>"0") and (kind_<>"1"):
+ errhelp "Will use default.";
+ errmessage "ES ERROR: don't know how to end";
+ kind_:="0";
+ fi
+ if kind_="0": pr--pl--cycle
+ elseif kind_="1":
+ save za_,zb_; pair za_,zb_;
+ za_=1/2[point length(pr) of pr,point 0 of pl]
+ +(1/2((point length(pr) of pr)-(point 0 of pl)) rotated 90);
+ zb_=1/2[point length(pl) of pl,point length 0 of pr]
+ +(1/2((point length(pl) of pl)-(point 0 of pr)) rotated 90);
+ pr{direction length(pr) of pr}..za_..{direction 0 of pl}pl
+ {direction length(pl) of pl}..zb_..{direction 0 of pr}cycle
+ fi
+enddef;
+% ---
+vardef opt_tensions(expr p,b) =
+% for a given B\'ezier segment |p| and a distance |b|, an optimal pair of
+% `tensions' $(\alpha,\beta)$ is found using least square method such that
+% |bez_edge|$(p,b,\alpha,\beta)$ (see below) approximates the edge of
+% a circular pen of diameter |b| traversing |p| (more on the employed
+% method be found in the article of B. Jackowski and M. Ry\'cko:
+% ``Labyrinth of \MF paths in outline,'' proceedings of the 8th European
+% \TeX Conference, Sept. 26--30, 1994, Gda\'nsk, Poland)
+%
+ save alpha_,beta_,gx_,gy_,n_,t_,ta_,tb_,tc_,td_,u_,v_,nu_,nv_,x_,y_;
+ numeric alpha_,beta_,n_,ta_,tb_,tc_,td_,
+ gx_[\\],gy_[\\],gx_.alpha[\\],gy_.alpha[\\],gx_.beta[\\],gy_.beta[\\],
+ u_.x,u_.y,v_.x,v_.y,nu_.x,nu_.y,nv_.x,nv_.y,
+ x_[\\],y_[\\];
+ n_:=5; % perhaps for |n_|$=\infty$ algebraic formulas can be derived, but...
+ (u_.x,u_.y)=(postcontrol 0 of p)-(point 0 of p);
+ (v_.x,v_.y)=(precontrol 1 of p)-(point 1 of p);
+ (nu_.x,nu_.y)=unitvector(u_.x,u_.y); (nv_.x,nv_.y)=unitvector(v_.x,v_.y);
+ for t_:=0 upto n_:
+ (x_[t_],y_[t_])=(point t_/n_ of p)+b*((udir t_/n_ of p) rotated -90);
+ endfor
+ for t_:=1 upto n_-1:
+ td_:=t_/n_; ta_:=1-td_; tb_:=3ta_*ta_*td_; tc_:=3ta_*td_*td_;
+ ta_:=ta_*ta_*ta_; td_:=td_*td_*td_;
+ gx_[t_]=ta_*x_0+tb_*(x_0+alpha_*u_.x)+tc_*(x_[n_]+beta_*v_.x)+td_*x_[n_];
+ gx_.alpha[t_]=tb_*nu_.x; gx_.beta[t_]=tc_*nv_.x;
+ gy_[t_]=ta_*y_0+tb_*(y_0+alpha_*u_.y)+tc_*(y_[n_]+beta_*v_.y)+td_*y_[n_];
+ gy_.alpha[t_]=tb_*nu_.y; gy_.beta[t_]=tc_*nv_.y;
+ endfor
+ 0=0 for t_:=1 upto n_-1:
+ +((gx_[t_]-x_[t_])*gx_.alpha[t_]+(gy_[t_]-y_[t_])*gy_.alpha[t_])/n_
+ endfor;
+ 0=0 for t_:=1 upto n_-1:
+ +((gx_[t_]-x_[t_])*gx_.beta[t_]+(gy_[t_]-y_[t_])*gy_.beta[t_])/n_
+ endfor;
+%| (u_.x,u_.y)=(postcontrol 0 of p)-(point 0 of p);|
+%| (v_.x,v_.y)=(precontrol 1 of p)-(point 1 of p);|
+%| ta_:=1/4length((u_.x,u_.y))+1/4length((v_.x,v_.y))|
+%| +1/4length((postcontrol 0 of p)-(precontrol 1 of p))|
+%| +1/4length((point 0 of p)-(point 1 of p));|
+%| message "accuracy=" & decimal|
+%| (0+for t_:=1 upto n_-1:+(((gx_[t_]-x_[t_])++(gy_[t_]-y_[t_]))/ta_)/n_|
+%| endfor);|
+%| message " alpha=" & decimal(alpha_) & " beta=" & decimal(beta_);|
+%| for t_:=0 upto n_: fill fullcircle scaled 3 shifted (x_[t_],y_[t_]); endfor|
+%| for t_:=1 upto n_-1: makelabel("g" & decimal(t_),(gx_[t_],gy_[t_])); endfor|
+ (alpha_,beta_)
+enddef;
+% ---
+vardef bez_edge(expr p,b,uv) =
+ save za_,zb_,u_,v_; pair za_,zb_; u_:=xpart(uv); v_:=ypart(uv);
+ za_=b*((udir 0 of p) rotated -90); zb_=b*((udir 1 of p) rotated -90);
+ ((point 0 of p)+za_) .. controls (u_[point 0 of p,postcontrol 0 of p]+za_)
+ and (v_[point 1 of p,precontrol 1 of p]+zb_) .. ((point 1 of p)+zb_)
+enddef;
+% ---
+def remove_global_loops(suffix E) =
+begingroup
+% warning: we don't trust too much in the results of ex. 14.17 from
+% The \MF{}book, hence a ``par force'' approach; there still exist
+% weird cases (e.g., local loops) which remain unsolved, but in practice
+% the following algorithm should suffice:
+ save opt_,ta_,tb_; pair opt_;
+ opt_:=(0,length(E));
+ for i_:=0 upto length(E)-1:
+ for j_:=i_+2 upto length(E)-1:
+ numeric ta_,tb_;
+ (ta_,tb_)=(subpath (i_,i_+1) of E)
+ intersectiontimes (subpath (j_,j_+1) of E);
+ if (ta_>0) and ((ta_+i_)>xpart(opt_)) and ((tb_+j_)<ypart(opt_)):
+ opt_:=(ta_+i_,tb_+j_);
+ fi
+ endfor
+ endfor
+ if xpart(opt_)>0:
+ E:=make_cycle(subpath(xpart(opt_),ypart(opt_)) of E);
+ fi
+endgroup
+enddef;
+% ---
+vardef make_edge@#(expr p,b)=
+ save E_,e_,ta_,tb_,tc_,td_; path E_,e_[\\];
+ for i_:=0 upto length(p)-1:
+ E_:=subpath (i_,i_+1) of p; e_[i_]=bez_edge(E_,b,opt_tensions(E_,b));
+ endfor
+ E_:=e_0;
+ for i_:=1 upto length(p)-1:
+ if (length(p)=2) and (cycle p): % this is a peculiar case, indeed!
+ numeric ta_,tb_,tc_,td_;
+ (ta_,tb_)=E_ intersectiontimes e_[i_];
+ (1-tc_,1-td_)=reverse(E_) intersectiontimes reverse(e_[i_]);
+ if ta_>=0:
+ E_:=(subpath(min(ta_,tc_),max(ta_,tc_)) of E_)
+ && (subpath(min(tb_,td_),max(tb_,td_)) of e_[i_]);
+ else: E_:=make_join@#(E_,e_[i_]);
+ fi
+ else:
+ numeric ta_,tb_;
+ (ta_,tb_)=(subpath(length(E_)-1,length(E_)) of E_)
+ intersectiontimes e_[i_];
+ if ta_>=0:
+ E_:=(subpath (0,length(E_)-1+ta_) of E_)
+ && (subpath(tb_,1) of e_[i_]);
+ else: E_:=make_join@#(E_,e_[i_]); fi
+ fi
+ endfor
+ if cycle p:
+ remove_global_loops(E_);
+ if not (cycle E_): E_:=make_cyclic_join@#(E_); fi
+ fi
+ E_
+enddef;
+% ---
+def expand_stroke(text P)(expr b) suffix R =
+begingroup interim autorounding:=0;
+ numeric PATH_.num; path PATH_[\\];
+ PATH_.num:=0; for P_:=P: PATH_[incr PATH_.num]:=touch_path(P_); endfor
+ if not path R0: numeric R.num; path R[\\]; fi
+ if (unknown R.num) or (unknown append_results): R.num:=0; fi
+ if unknown join_kind: save join_kind; join_kind=0; fi
+ if unknown end_kind: save end_kind; end_kind=0; fi
+ for i_:=1 upto PATH_.num:
+ if not cycle PATH_[i_]:
+ R[incr R.num]:=make_end[end_kind]
+ (make_edge[join_kind](PATH_[i_],b),
+ reverse make_edge[join_kind](PATH_[i_],-b));
+ else:
+ R[incr R.num]:=make_edge[join_kind](PATH_[i_],b);
+ R[incr R.num]:=reverse make_edge[join_kind](PATH_[i_],-b);
+ fi
+ endfor
+ for i_:=1 upto R.num: R[i_]:=clean_path(clean_path(R[i_])); endfor
+endgroup
+enddef;
+% ---
+def change_weight(text P)(expr b) suffix R =
+begingroup interim autorounding:=0;
+ numeric PATH_.num; path PATH_[\\];
+ PATH_.num:=0; for P_:=P: PATH_[incr PATH_.num]:=touch_path(P_); endfor
+ if not path R0: numeric R.num; path R[\\]; fi
+ if (unknown R.num) or (unknown append_results): R.num:=0; fi
+ if unknown join_kind: save join_kind; join_kind=0; fi
+ for i_:=1 upto PATH_.num:
+% non-cyclic paths are ignored
+ if cycle PATH_[i_]: R[incr R.num]:=make_edge[join_kind](PATH_[i_],b); fi
+ endfor
+endgroup
+enddef;
+% ---
+def info_ro expr s = if tracingremoving>0: message s; message ""; fi enddef;
+def info_es expr s = if tracingexpanding>0: message s; message ""; fi enddef;
+% ---
+% DEFAULTS:
+% ---
+def roex_default text t =
+ forsuffixes S_:=t:
+ if str S_ = "good_colors":
+% the formula |good_colors(p,q) and good_colors(q,p)| must be |false|!
+ vardef good_colors(expr i,o) = ((i>=1) and (o<=0)) enddef;
+ elseif str S_ = "touch_path":
+ vardef touch_path(expr p) = p enddef;
+ elseif str S_ = "background_color": background_color:=0;
+ elseif str S_ = "miter_size":
+ miter_size:=10pixels_per_inch/72; % i.e., 10bp
+% incidentally, |10bp| would convert to |10.00002| during export at |300dpi|
+ elseif str S_ = "epsil.ang": epsil.ang:=1/10; % in degrees
+ elseif str S_ = "epsil.dist": epsil.dist:=1/10pt; % ca |2/5|pxl at |300dpi|
+ elseif str S_ = "epsil.time": epsil.time:=1/100;
+ elseif str S_ = "epsil.len": epsil.len:=1/1000; % used in |turn_ang|
+ elseif str S_ = "max_idx": max_idx:=125;
+ elseif str S_ = "enc":
+% |enc| is a prefix of a data structure used in checking tangent
+% points and searching for the leftmost edge; |enc.pth| is in both
+% cases scaled differently
+ vardef enc.pth = fullcircle enddef; enc.len:=length(enc.pth);
+ fi
+ endfor
+enddef;
+%
+roex_default good_colors, touch_path, background_color, miter_size,
+ epsil.ang, epsil.dist, epsil.time, epsil.len, max_idx, enc;
+% ---
+numeric append_results; % initially unknown
+newinternal tracingleftmost; tracingleftmost:=0;
+newinternal tracingremoving; tracingremoving:=0;
+newinternal tracingexpanding; tracingexpanding:=0;
+% ---
+endinput
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/0roexsam.doc b/graphics/MF-PS/roex/roexsamp/0roexsam.doc
new file mode 100644
index 0000000000..86336cf613
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/0roexsam.doc
@@ -0,0 +1,69 @@
+This file belongs to the ROEX package.
+
+-----------------------------------------------------------------------------
+
+The directory ROEXSAMP contains this file (0ROEXSAM.DOC) and 14 examples
+of using ROEX with the MFTOEPS package.
+
+WARNING: processing some of the files may last a while; in braces are
+shown computing times for mf386 (version 2.71 [3c-beta5]) run on 486 Intel PC
+with 66MHz clock.
+
+ ES-01.MF, ``SQUARE'' (3 seconds):
+ A trivial example, expanding stroke applied to a square.
+ ES-02.MF, ``PARALLELOGRAM'' (4 seconds):
+ Another trivial example: expanding stroke applied
+ to a parallelogram.
+ ES-03.MF, ``COGWHEEL'' (7 seconds):
+ Expanding stroke applied to a somewhat complex object.
+ RO-01.MF, ``PROPELLER'' (14 seconds):
+ Removing overlaps applied to a circle and three rectangles;
+ rectangles are positively oriented, circle is negatively
+ oriented and has weight |2|.
+ RO-02.MF, ``ENCIRCLED CROSS 1'' (4 seconds):
+ Removing overlaps applied to a positively oriented circle
+ and two negatively oriented rectangles.
+ RO-03.MF, ``ENCIRCLED CROSS 2'' (4 seconds):
+ An example very similar to RO-02.MF; removing overlaps applied
+ to a negatively oriented circle and two positively oriented
+ rectangles, background colour is set to |1| (default is |0|).
+ RO-04.MF, ``EOFILL'' (30 seconds):
+ Removing overlaps performed in two stages; emulates
+ even-odd filling rule
+ RO-05.MF, ``GERBERA'' (3 minutes, 51 seconds):
+ Areas covered a specified number of times are collected
+ separately using the macro |recombine_edges| (performing
+ the last step of removing overlaps), and each area is painted
+ with a different colour, yielding a gerbera-like form.
+ RO-06.MF, ``EL PALO ALTO TREE'' (57 seconds):
+ A tough example (see remarks in the code) excerpted from
+ The \MF{}book, pages 124 thru 126.
+ RO-07.MF, ``LOGO OF JOURNAL OF ALGORITHMS'' (28 seconds):
+ Another example excerpted from The \MF{}book,
+ pages 137 thru 139.
+ ROES-01.MF, ``SUN'' (55 seconds):
+ An example making use of both expanding stroke
+ and removing overlaps.
+ ROES-02.MF, ``DOORMAT'' (1 minute, 34 seconds):
+ Another example making use of both expanding stroke
+ and removing overlaps;
+ ROES-03.MF, ``OLYMPIC CIRCLES'' (1 minute, 1 second):
+ Yet another example making use of both expanding
+ stroke and removing overlaps; it also demonstrates
+ repositioning of the picture in such a way that the lower
+ left corner of the bounding box coincides with the origin
+ of coordinate system.
+ ROES-04.MF, ``STAR FLOWERS'' (3 minutes, 4 seconds):
+ An example of removing overlaps of a single
+ self-intersecting curve; three EPS files are generated.
+
+You are entitled to do with these files whatever you wish.
+If you alter a file, however, please remove the comment line:
+
+ `This file belongs to the ROEX package.'
+
+in order to avoid mess.
+
+-----------------------------------------------------------------------------
+
+END OF THE 0ROEXSAMP.DOC FILE
diff --git a/graphics/MF-PS/roex/roexsamp/README b/graphics/MF-PS/roex/roexsamp/README
new file mode 120000
index 0000000000..322b711309
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/README
@@ -0,0 +1 @@
+0roexsam.doc \ No newline at end of file
diff --git a/graphics/MF-PS/roex/roexsamp/es-01.mf b/graphics/MF-PS/roex/roexsamp/es-01.mf
new file mode 100644
index 0000000000..c2ccc77d17
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/es-01.mf
@@ -0,0 +1,29 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% ES-01.MF, ``SQUARE'':
+% A trivial example, expanding stroke applied to a square.
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingexpanding:=1;
+% ---
+beginchar("0",cm#,cm#,0);
+ expand_stroke (unitsquare xscaled w yscaled h) (1mm) R;
+% find_BB make_list(1,R.num) R;
+ find_BB R1,R2; % R.num=2
+ write_preamble jobname;
+ for i:=1 upto R.num:
+ fix_draw_cmyk if check_turn(R[i])>0: 0,1,1,0 else: 1,1,0,0 fi;
+ draw_C R[i];
+ if proofing>0:
+ for j:=0 upto length(R[i])-1:
+ makelabel(decimal(j) & "/" & decimal(i),point j of R[i]);
+ endfor
+ fi
+ endfor
+ write_postamble;
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/es-02.mf b/graphics/MF-PS/roex/roexsamp/es-02.mf
new file mode 100644
index 0000000000..037091afe1
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/es-02.mf
@@ -0,0 +1,32 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% ES-02.MF, ``PARALLELOGRAM'':
+% Another trivial example: expanding stroke applied to a parallelogram.
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingexpanding:=1;
+% ---
+beginchar("0",1/10in#,in#,0);
+ path p; p=((1/2w,0)--(1/4w,1/4h)--(0,1/2h)--(1/2w,h)--(w,1/2h)--cycle);
+ miter_size:=w;
+ expand_stroke (p) (2/5w) R;
+% change_weight (p) (2/5w) R;
+ find_BB make_list(1,R.num) R;
+ write_preamble jobname;
+ fix_draw_cmyk 0,0,0,1; draw_C p;
+ for i:=1 upto R.num:
+ fix_draw_cmyk if check_turn(R[i])>0: 0,1,1,0 else: 1,1,0,0 fi;
+ draw_C R[i];
+ if proofing>0:
+ for j:=0 upto length(R[i])-1:
+ makelabel(decimal(j) & "/" & decimal(i),point j of R[i]);
+ endfor
+ fi
+ endfor
+ write_postamble;
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/es-03.mf b/graphics/MF-PS/roex/roexsamp/es-03.mf
new file mode 100644
index 0000000000..b21da0d9ba
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/es-03.mf
@@ -0,0 +1,43 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% ES-03.MF, ``COGWHEEL'':
+% Expanding stroke applied to a somewhat complex object, |miter_size|
+% set to zero.
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingexpanding:=1;
+% ---
+vardef flex_polyg(expr n,a) =
+ save zz; pair zz[\\];
+ for i:=0 upto n-1:
+ zz[i]:=up rotated (i*(360/n));
+ endfor
+ (zz0
+ for i:=1 upto n:
+ {(zz[i mod n]-zz[i-1]) rotated a}..{(zz[i mod n]-zz[i-1]) rotated -a}
+ if i=n: cycle else: zz[i] fi
+ endfor
+ ) scaled .5
+enddef;
+% ---
+beginchar("0",in#,in#,0);
+ b:=.5mm; path p; p=flex_polyg(17,60) scaled w shifted (1/2w,1/2h);
+ miter_size:=0bp; expand_stroke (p) (b) R;
+% miter_size:=0bp; change_weight(p) (b) R;
+ find_BB R1,R2;
+ write_preamble jobname;
+ draw_C R1,R2;
+ write_postamble;
+ for i:=1,2:
+ if proofing>0:
+ for j:=0 upto length(R[i])-1:
+ makelabel(decimal(j) & "/" & decimal(i),point j of R[i]);
+ endfor
+ fi
+ endfor
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/ro-01.mf b/graphics/MF-PS/roex/roexsamp/ro-01.mf
new file mode 100644
index 0000000000..6b4551eccd
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/ro-01.mf
@@ -0,0 +1,26 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% RO-01.MF, ``PROPELLER'':
+% Removing overlaps applied to a circle and three rectangles; rectangles
+% are positively oriented, circle is negatively oriented and has weight |2|.
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingremoving:=1;
+% ---
+beginchar("0",in#,in#,0);
+ path A,B,C,D;
+ A=unitsquare xscaled 1/5w yscaled h shifted (2/5w,0);
+ B=A rotatedaround((1/2w,1/2h), 60);
+ C=B rotatedaround((1/2w,1/2h), 60);
+ D=reverse fullcircle scaled 3/4w shifted (1/2w,1/2h);
+ remove_overlap (A,B,C,D) ((4,2)) R;
+ find_BB make_list(1,R.num) R;
+ write_preamble jobname;
+ fill_C make_list(1,R.num) R;
+ write_postamble;
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/ro-02.mf b/graphics/MF-PS/roex/roexsamp/ro-02.mf
new file mode 100644
index 0000000000..ce5a058219
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/ro-02.mf
@@ -0,0 +1,33 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% RO-02.MF, ``ENCIRCLED CROSS 1'':
+% Removing overlaps applied to a positively oriented circle and two
+% negatively oriented rectangles.
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingremoving:=1;
+% ---
+beginchar("0",in#,in#,0);
+ path A,B,C;
+ A=fullcircle scaled w shifted (1/2w,1/2h);
+ B=reverse unitsquare xscaled 1/5w yscaled 3/5w shifted (2/5w,1/5w);
+ C=B rotatedaround((1/2w,1/2h), 90);
+ remove_overlap (A,B,C) () R;
+ set_BB 0,0,w,h;
+ write_preamble jobname;
+ for i:=1 upto R.num:
+ fix_draw_cmyk if check_turn(R[i])>0: 0,1,1,0 else: 1,1,0,0 fi;
+ draw_C R[i];
+ if proofing>0:
+ for j:=0 upto length(R[i])-1:
+ makelabel(decimal(j) & "/" & decimal(i),point j of R[i]);
+ endfor
+ fi
+ endfor
+ write_postamble;
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/ro-03.mf b/graphics/MF-PS/roex/roexsamp/ro-03.mf
new file mode 100644
index 0000000000..988c018b1a
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/ro-03.mf
@@ -0,0 +1,34 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% RO-03.MF, ``ENCIRCLED CROSS 2'':
+% An example very similar to RO-02.MF; removing overlaps applied to
+% a negatively oriented circle and two positively oriented rectangles,
+% background colour is set to |1| (default is |0|).
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingremoving:=1;
+% ---
+beginchar("0",in#,in#,0);
+ path A,B,C;
+ A=reverse fullcircle scaled w shifted (1/2w,1/2h);
+ B=unitsquare xscaled 1/5w yscaled 3/5w shifted (2/5w,1/5w);
+ C=B rotatedaround((1/2w,1/2h), 90);
+ background_color:=1; remove_overlap (A,B,C) () R;
+ set_BB 0,0,w,h;
+ write_preamble jobname;
+ for i:=1 upto R.num:
+ fix_draw_cmyk if check_turn(R[i])>0: 0,1,1,0 else: 1,1,0,0 fi;
+ draw_C R[i];
+ if proofing>0:
+ for j:=0 upto length(R[i])-1:
+ makelabel(decimal(j) & "/" & decimal(i),point j of R[i]);
+ endfor
+ fi
+ endfor
+ write_postamble;
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/ro-04.mf b/graphics/MF-PS/roex/roexsamp/ro-04.mf
new file mode 100644
index 0000000000..7704db948a
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/ro-04.mf
@@ -0,0 +1,49 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk roex_default
+% RO-04.MF, ``EOFILL'':
+% Removing overlaps performed in two stages: first stage removes overlaps
+% using even-odd filling rule, the second stage restores default meanings
+% of |good_colors| and |touch_path| and performs ``traditional'' removing
+% overlaps on the result of stage 1 and a positively oriented rectangle.
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingremoving:=1;
+% ---
+beginchar("0",in#,in#,0);
+ path A,B,C,D,E,F;
+ A=fullcircle scaled 1w shifted (1/2w,1/2h);
+ B=fullcircle scaled 4/5w shifted (1/2w,1/2h);
+ C=fullcircle scaled 3/5w shifted (1/2w,1/2h);
+ D=fullcircle scaled 2/5w shifted (1/2w,1/2h);
+ E=unitsquare xscaled 1/5w yscaled 9/10h shifted (2/5w,1/20h);
+ F=unitsquare xscaled 7/5w yscaled 1/5h shifted (-1/5w,2/5h);
+%
+% STAGE 1: remove overlaps for |A|, |B|, |C|, |D| and |E| using
+% the `eofill' rule (the re-definition of |touch_path| is superfluous here,
+% but recommended in a general case):
+ vardef good_colors(expr i,o) = odd(i) and odd(o+1) enddef;
+ vardef touch_path(expr p) = pos_turn(p) enddef;
+ remove_overlap (A,B,C,D,E) () R;
+% STAGE 2: remove overlaps for |F| and the paths resulting from the stage 1:
+ roex_default good_colors, touch_path;
+ remove_overlap (F,make_list(1,R.num) R) () R;
+%
+ find_BB make_list(1,R.num) R;
+ write_preamble jobname;
+ fix_fill_cmyk 0,0,0,1/10;
+ fill_C make_list(1,R.num) R;
+ for i:=1 upto R.num:
+ fix_draw_cmyk if check_turn(R[i])>0: 0,1,1,0 else: 1,1,0,0 fi;
+ draw_C R[i];
+ if proofing>0:
+ for j:=0 upto length(R[i])-1:
+ makelabel(decimal(j) & "/" & decimal(i),point j of R[i]);
+ endfor
+ fi
+ endfor;
+ write_postamble;
+endchar;
+end.
+%%\end
diff --git a/graphics/MF-PS/roex/roexsamp/ro-05.mf b/graphics/MF-PS/roex/roexsamp/ro-05.mf
new file mode 100644
index 0000000000..bac4bb8d7d
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/ro-05.mf
@@ -0,0 +1,45 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% RO-05.MF, ``GERBERA'':
+% Non-standard application of removing overlaps; areas covered a specified
+% number of times are collected separately using the macro |recombine_edges|
+% (performing the last step of removing overlaps), and each area is painted
+% with a different colour, yielding a gerbera-like form.
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingremoving:=1;
+% ---
+beginchar("0",in#,in#,0);
+ path R[\\],V[\\][\\];
+ N:=9;
+ R.num:=0;
+ R[incr R.num]=fullcircle xscaled 1/5w yscaled h shifted (1/2w,1/2h);
+ for i:=1 upto N-1:
+ R[incr R.num]=R[R.num-1] rotatedaround((0.5w,.5h), 180/N);
+ endfor
+%
+ remove_overlap (make_list(1,R.num)R)() R; % dummy result
+ col.min:=infinity; col.max:=-infinity;
+ for i:=-EDGE_.num upto EDGE_.num : if i<>0:
+ col.min:=min(EDGE_.col[i],col.min);
+ col.max:=max(EDGE_.col[i],col.max);
+ fi endfor;
+ col.min:=max(1,col.min);
+ for k:=col.min upto col.max:
+ vardef good_colors(expr i,j) = (i=k) enddef;
+ message "recombine_edges: color=" & decimal(k); recombine_edges(V[k]);
+ endfor;
+ set_BB 0,0,w,h; write_preamble jobname;
+ for k:=col.min upto col.max:
+ if V[k]num>0:
+ fix_fill_cmyk 0,3/4((((k-col.min)/(col.max-col.min))**1/2)[1,0]),1,0;
+ fill_C make_list(1,V[k]num)V[k];
+ fi
+ endfor
+ write_postamble;
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/ro-06.mf b/graphics/MF-PS/roex/roexsamp/ro-06.mf
new file mode 100644
index 0000000000..7007cd233b
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/ro-06.mf
@@ -0,0 +1,150 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+%%% draw fix_line_join fix_line_cap fix_line_width
+% RO-06.MF, ``EL PALO ALTO TREE'':
+% A tough example (see remarks below) excerpted from The \MF{}book, pages
+% 124 thru 126.
+%% % an innocent formatting trick: the underscore character ending a name
+%% % will be typeset as an superscript asterisk
+%% \let\oriunderscore\_
+%% \newif\ifbgroupopen \bgroupopenfalse
+%% \def\altdblbackslash#1{\bgroup\bgroupopentrue\it#1}
+%% \def\optegroup{\ifbgroupopen\egroup\fi}
+%% \def\underscoreasasterisk#1{%
+%% \ifx#1\relax\optegroup^*\else\oriunderscore#1\fi}
+%% \def\\#1{%
+%% \let\_\underscoreasasterisk
+%% \altdblbackslash{#1\relax}\optegroup
+%% \let\_\oriunderscore}
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingremoving:=1;
+% ---
+% REMARKS:
+% 1. There arise very close points during the intersecting process,
+% hence |epsil.dist| is adjusted (see also point 2).
+% 2. Note that:
+% a) |turningnumber(branch1)=1| but |turningnumber(reverse branch1)=0|
+% (sic!);
+% b) for the second resulting path, |R2| (the tree), |turningnumber(R2)=1|
+% while |check_turn(R2)=-1|, which is the desired value as the tree
+% is unfilled (oh, these tiny loops!);
+% c) the minimal resulting interval, i.e., the time distance
+% between two neighbouring points of intersection is dangerously
+% small, namely, |0.00032|; usually the value smaller than the bound,
+% by default equal to |0.01|, portends a collaps of the algorithm,
+% fortunately not in this case (set |tracingremoving:=2| for more
+% information on intervals and secants).
+epsil.dist:=1/50pt;
+% show_turningnumbers_and_turn_checks:=1;
+% mark_trunk_close_points:=1;
+% ---
+beginchar ("0",1/2in#,5/4in#,0);
+ path branch[\\], oval;
+%
+% prepare data:
+ branch0 = % i.e., trunk
+ (0,660)---(-12,70)..{curl 5}(-28,-8)
+ & flex((-28,-8),(-16,-4),(-10,-11))
+ & flex((-10,-11),(0,-5),(14,-10))
+ & flex((14,-10),(20,-6),(29,-11))
+ & (29,-11){curl 4}..(10,100)---cycle;
+ branch1= flex((0,660),(-9,633),(-22,610))
+ & flex((-22,610),(-3,622),(17,617))
+ & flex((17,617),(7,637),(0,660)) & cycle;
+ branch2=flex((30,570),(10,590),(-1,616))
+ & flex((-1,616),(-11,592),(-29,576),(-32,562))
+ & flex((-32,562),(-10,577),(30,570)) & cycle;
+ branch3=flex((-1,570),(-17,550),(-40,535))
+ & flex((-40,535),(-45,510),(-60,477))
+ & flex((-60,477),(-20,510),(40,512))
+ & flex((40,512),(31,532),(8,550),(-1,570)) & cycle;
+ branch4=flex((0,509),(-14,492),(-32,481))
+ & flex((-32,481),(-42,455),(-62,430))
+ & flex((-62,430),(-20,450),(42,448))
+ & flex((42,448),(38,465),(4,493),(0,509)) & cycle;
+ branch5=flex((-22,470),(-23,435),(-44,410))
+ & flex((-44,410),(-10,421),(35,420))
+ & flex((35,420),(15,455),(-22,470)) & cycle;
+ branch6=flex((18,375),(9,396),(5,420))
+ & flex((5,420),(-5,410),(-50,375),(-50,350))
+ & flex((-50,350),(-25,375),(18,375)) & cycle;
+ branch7=flex((0,400),(-13,373),(-30,350))
+ & flex((-30,350),(0,358),(30,350))
+ & flex((30,350),(13,373),(0,400)) & cycle;
+ branch8=flex((50,275),(45,310),(3,360))
+ & flex((3,360),(-20,330),(-70,300),(-100,266))
+ & flex((-100,266),(-75,278),(-60,266))
+ & flex((-60,266),(0,310),(50,275)) & cycle;
+ branch9=flex((10,333),(-15,290),(-43,256))
+ & flex((-43,256),(8,262),(58,245))
+ & flex((58,245),(34,275),(10,333)) & cycle;
+ branch10=flex((8,262),(-21,249),(-55,240))
+ & flex((-55,240),(-51,232),(-53,220))
+ & flex((-53,220),(-28,229),(27,235))
+ & flex((27,235),(16,246),(8,262)) & cycle;
+ branch11=flex((0,250),(-25,220),(-70,195))
+ & flex((-70,195),(-78,180),(-90,170))
+ & flex((-90,170),(-5,188),(74,183))
+ & flex((74,183),(34,214),(0,250)) & cycle;
+ branch12=flex((8,215),(-35,175),(-72,155))
+ & flex((-72,155),(-75,130),(-92,110),(-95,88))
+ & flex((-95,88),(-65,117),(-54,104))
+ & flex((-54,104),(10,151),(35,142))
+ ..flex((42,130),(60,123),(76,124))
+ & flex((76,124),(62,146),(26,180),(8,215)) & cycle;
+%
+ for i:=0 upto 12:
+ branch[i]:=neg_turn branch[i] shifted (150,50) scaled (w/300);
+ endfor
+ oval=superellipse((w,1/2h),(1/2w,h),(0,1/2h),(1/2w,0),4/5);
+%
+% remove overlaps and (optionally) show |turningnumber|s and |turn_check|s:
+ remove_overlap (make_list(0,12)branch,oval)() R;
+ if known show_turningnumbers_and_turn_checks:
+ begingroup
+ interim autorounding:=0;
+ show (turningnumber(branch1), turningnumber(reverse branch1));
+ for i:=1 upto R.num: show i,(turningnumber R[i],check_turn R[i]); endfor;
+ endgroup;
+ fi
+%
+% begin export to EPS:
+ find_BB oval;
+ write_preamble jobname;
+ fix_line_join 1; fix_line_cap 1;
+ fix_line_width 1/50pt;
+% paint the picture:
+ fix_fill_cmyk 0,0,0,1/6;
+ fill_C make_list(1,R.num)R;
+ for i:=1 upto R.num:
+ if proofing=0:
+ fix_draw_cmyk if check_turn(R[i])>0: 0,1,1,0 else: 1,1,0,0 fi;
+ draw_C R[i];
+ else:
+ for j:=0 upto length(R[i])-1:
+ makelabel(decimal(j) & "/" & decimal(i),point j of R[i]);
+ endfor
+ fi
+ endfor
+%
+% mark (optionally) dangerously close points:
+ if known mark_trunk_close_points:
+ fix_fill_cmyk 0,0,0,1; fix_draw_cmyk 0,0,0,1;
+ for j:=13,14,17,18:
+ z[j]=point TIME_1tim[j] of PATH_1;
+ fill_C fullcircle scaled 1/50pt shifted z[j];
+ endfor
+ z.a=(1pt,0); z.b=(1/20pt,0); z.c=(1/5pt,1/10pt); z.d=(1/5pt,-1/10pt);
+ for zz:=1/2[z13,z14],1/2[z17,z18]:
+ draw_C (zz-z.a)--(zz-z.b), (zz-z.c)--(zz-z.b)--(zz-z.d);
+ endfor
+ fi
+% end export to EPS:
+ write_postamble;
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/ro-07.mf b/graphics/MF-PS/roex/roexsamp/ro-07.mf
new file mode 100644
index 0000000000..5697a6462a
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/ro-07.mf
@@ -0,0 +1,102 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% RO-07.MF, ``LOGO OF JOURNAL OF ALGORITHMS'':
+% Another example excerpted from The \MF{}book, pages 137 thru 139;
+% |penstroke| is redefined in such a way that instead of creating a bitmap
+% picture, it stores respective curves; two points were moved, |z.a8l| and
+% |z.a8r| (see comments with a remark ``intrusion''), in order to avoid
+% partially overlaping paths, as ROEX does not cope with such data.
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingremoving:=1;
+% ---
+def penstroke text t =
+ forsuffixes e = l,r: path_.e:=t; endfor
+ if cycle path_.l: R[incr R.num]:=path_.l.t_; R[incr R.num]:=path_.r.t_;
+ else: R[incr R.num]:=path_.l -- reverse path_.r -- cycle; fi
+ enddef;
+% ---
+beginchar("0",29mm#,25mm#,0);
+ path R[\\]; R.num:=0;
+%
+ thick#:=2mm#; thin#:=5/4mm#;
+ define_whole_blacker_pixels(thick,thin);
+ forsuffixes $=a,b,c: transform $;
+ forsuffixes e=l,r: path $e,$'e; numeric t$[\\]e;
+ endfor
+ endfor
+ penpos1(thick,0); penpos2(thick,90); penpos3(thick,180); penpos4(thick,270);
+ penpos5(thick,0); penpos6(thick,90); penpos7(thick,180); penpos8(thick,270);
+ x2=x4=x6=x8=.5[x5,x7]=.5w; x1r=w; x3r=0;
+ x5-x7=y6-y8;
+ y1=y3=y5=y7=.5[y6,y8]=.5h; y2r=h; y4r=0;
+ y6r=.75h;
+ forsuffixes e=l,r: a.e=b'e=c'e=superellipse (z1e,z2e,z3e,z4e,.75);
+ a'e=b.e=c.e=superellipse (z5e,z6e,z7e,z8e,.72);
+ endfor
+ penpos a1(thin,0); penpos a5(whatever,-90); penpos a9(thin,180);
+ x.a1l-x.a9l=1/3(x5l-x7l); x.a5=.5w; y.a1=y.a9; y.a5r=4/7h;
+ x.a3l=x.a1l; x.a3r=x.a1r; x.a4r=1/6[x.a3r,x1l]; x0=.5w; y0=.52h;
+ x.a6l+x.a4l=x.a6r+x.a4r=x.a7l+x.a3l=
+ x.a7r+x.a3r=x.a9+x.a1=w;
+ y.a3r=y.a4r=y.a6r=y.a7r=.2[y2l,y0]; y.a3l=y.a4l=y.a6l=y.a7l=y.a3r-thin;
+ z.a4l=z.a4r+(thin,0) rotated(angle(z.a4r-z.a5r)+90)+whatever*(z.a4r-z.a5r);
+ z.a4l-z.a5l=whatever*(z.a4r-z.a5r);
+ z=a.r intersectionpoint (z0--(w,0));
+ y.a1-y.a5=length(z-z0);
+ b=identity shifted (0,y0-y.a1) rotatedaround(z0,90-angle(z0-(w,0)));
+ c=b reflectedabout (z2,z4);
+ for n=1,3,4,5,6,7,9: forsuffixes e=l,,r: forsuffixes $=b,c:
+ z$[n]e=z.a[n]e transformed $;
+ endfor endfor endfor
+ forsuffixes e=l,r: forsuffixes $=a,b,c:
+% intrusion: the primed entries are stored for further use (see below)
+ z$2e'=$l intersectionpoint (z$1e--z$3e);
+ z$8e'=$l intersectionpoint (z$9e--z$7e);
+% end of intrusion
+ z$2e=$r intersectionpoint (z$1e--z$3e);
+ z$8e=$r intersectionpoint (z$9e--z$7e);
+ t$1e=xpart($e intersectiontimes (z$1l--z$3l));
+ t$9e=xpart($e intersectiontimes (z$9l--z$7l));
+ t$4e=xpart($'e intersectiontimes (z$5r--z$4l));
+ t$6e=xpart($'e intersectiontimes (z$5r--z$6l));
+ endfor endfor
+ penstroke subpath(t.a9e,t.b6e) of a.e;
+ penstroke subpath(t.b4e,t.c4e) of b'e;
+ penstroke subpath(t.c6e,t.a1e+8) of c'e;
+ penstroke subpath(t.a6e,t.b9e) of a'e;
+ penstroke subpath(t.b1e,t.c1e) of b.e;
+ penstroke subpath(t.c9e,t.a4e+8) of c.e;
+% intrusion: correction of offending nodes, i.e., |z.a8l|, |z.a8r|,
+% |z.a8l|, and |z.a8r|
+ x.a8l:=x.a8l'; x.a8r:=x.a8r'; y.a8l:=y.a8l'; y.a8r:=y.a8r'+(y2r-y2);
+ x.a2l:=x.a2l'; x.a2r:=x.a2r'; y.a2l:=y.a2l'; y.a2r:=y.a2r'+(y2r-y2);
+% end of intrusion
+ forsuffixes $=a,b,c:
+% |penlabels($1,$2,$3,$4,$5,$6,$7,$8,$9);|
+ penstroke z$2e--z$3e--z$4e--z$5e--z$6e--z$7e--z$8e;
+ endfor
+% |penlabels(range 0 thru 8);|
+ vardef touch_path expr p = pos_turn p enddef;
+ remove_overlap (make_list(1,R.num)R) () R;
+ find_BB make_list(1,R.num)R;
+ write_preamble jobname;
+ fix_fill_cmyk 0,0,0,1/6;
+ fill_C make_list(1,R.num)R;
+ fix_line_width 1/10pt;
+ for i:=1 upto R.num:
+ fix_draw_cmyk if check_turn R[i]>0: 0,1,1,0 else: 1,1,0,0 fi;
+ draw_C R[i];
+ if proofing>0:
+ for j:=0 upto length(R[i])-1:
+ makelabel(decimal(j) & "/" & decimal(i),point j of R[i]);
+ endfor
+ fi
+ endfor
+ write_postamble;
+endchar;
+end.
+%%\end
+
diff --git a/graphics/MF-PS/roex/roexsamp/roes-01.mf b/graphics/MF-PS/roex/roexsamp/roes-01.mf
new file mode 100644
index 0000000000..bac1a14bfd
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/roes-01.mf
@@ -0,0 +1,38 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% ROES-01.MF, ``SUN'':
+% An example making use of both expanding stroke and removing overlaps.
+% ---
+input mftoeps; eps_mode_setup; input roex;
+tracingexpanding:=1; tracingremoving:=1;
+% ---
+beginchar("0",in#,in#,0);
+ path Q,R[\\]; R.num:=0;
+ M:=12; % number of half-periods of a sine wave
+ N:=11; % number of gaps
+ H:=h/(2N); W=1.2w;
+ Q:=reverse for i:=0 upto M: if i>0: .. fi
+ ((i/M)[1/2(w-W),w-1/2(w-W)],1/2sind(90(i mod 4))*H)
+ endfor;
+%
+ expand_stroke(Q)(1/2H)R; Q:=reverse R1; R.num:=0;
+ if proofing>0:
+ for j:=0 upto length(Q)-1: makelabel("Q" & decimal(j),point j of Q); endfor
+ fix_line_width 1; draw_C Q;
+ fi
+ for i:=1 upto N: R[incr R.num]:=Q shifted (0,(2i-1)*H); endfor
+ R[incr R.num]:=fullcircle scaled w shifted (.5w,.5h);
+%
+ remove_overlap(make_list(1,R.num) R)() R;
+ find_BB make_list(1,R.num) R;
+ write_preamble jobname;
+ for i:=1 upto R.num:
+ fix_fill_cmyk 0,((i-1)/(R.num-1))[1,0],1,0; fill_C R[i];
+ endfor;
+ write_postamble;
+endchar;
+end.
+%%\end
diff --git a/graphics/MF-PS/roex/roexsamp/roes-02.mf b/graphics/MF-PS/roex/roexsamp/roes-02.mf
new file mode 100644
index 0000000000..f5dda5c552
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/roes-02.mf
@@ -0,0 +1,33 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C draw_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% ROES-02.MF, ``DOORMAT'':
+% Another example making use of both expanding stroke and removing overlaps;
+% ---
+input mftoeps; eps_mode_setup; input roex;
+tracingexpanding:=1; tracingremoving:=1;
+% ---
+beginchar("0",1in#,1in#,0);
+ path A[\\],B[\\];
+ A.n:=5; B.n:=5; % large values may cause exceedingly long processing...
+ A.b:=(1/(2A.n+1))*w; B.b:=(1/(2B.n+1))*h;
+ for i:=1 upto A.n:
+ A[i]:=((0,0)..(-1/2A.b,1/3h)..(1/2A.b,2/3h)..(0,h)) shifted ((2i-.5)*A.b,0);
+ endfor
+ for i:=1 upto B.n:
+ B[i]:=((0,0)..(1/3w,-1/2B.b)..(2/3w,1/2B.b)..(w,0)) shifted (0,(2i-.5)*B.b);
+ endfor
+ expand_stroke(make_list(1,A.n)A, make_list(1,B.n)B)(1/2A.b)R;
+ remove_overlap(make_list(1,R.num)R)()R;
+ find_BB make_list(1,R.num) R;
+ write_preamble jobname;
+ for i:=1 upto R.num:
+ fix_draw_cmyk if check_turn(R[i])>0: 0,1,1,0 else: 1,1,0,0 fi;
+ draw_C R[i];
+ endfor;
+ write_postamble;
+endchar;
+end.
+%%\end
diff --git a/graphics/MF-PS/roex/roexsamp/roes-03.mf b/graphics/MF-PS/roex/roexsamp/roes-03.mf
new file mode 100644
index 0000000000..7df45b013a
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/roes-03.mf
@@ -0,0 +1,49 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw write_preamble write_postamble find_BB set_BB fill_C clip_C
+%%% draw fix_fill_cmyk fix_draw_cmyk
+% ROES-03.MF, ``OLYMPIC CIRCLES'':
+% Yet another example making use of both expanding stroke and removing
+% overlaps; it also demonstrates repositioning of the picture in such
+% a way that the lower left corner of the bounding box coincides with
+% the origin of coordinate system.
+input mftoeps; eps_mode_setup; input roex;
+tracingremoving:=1; tracingexpanding:=1;
+% ---
+beginchar("0",in#,in#,0); % temporary values
+ path A[];
+ for i:=1,2,3,4,5:
+ A[i]:=fullcircle scaled w shifted
+ (floor(i/4)*(1/2sqrt(3)*w,0)+1/2w*(up rotated (120i+60)));
+ endfor
+ expand_stroke (A1,A2,A3,A4,A5) (.5mm) R;
+ remove_overlap (make_list(1,R.num)R) () R;
+% setting of intermediate colors:
+ k:=0; % the number of intermediate colors
+ C[incr k]=0; M[k]=1; Y[k]=1; K[k]:=0;
+ C[incr k]=0; M[k]=0; Y[k]=1; K[k]:=0;
+ C[incr k]=0.25; M[k]=0; Y[k]=0.75; K[k]:=0;
+ C[incr k]=1; M[k]=0.5; Y[k]=0; K[k]:=0;
+ C[incr k]=0.3; M[k]=1; Y[k]=0; K[k]:=0;
+ l:=30; % the number of interpolation steps
+ m=l*(k-1); % the number of strips
+ find_BB make_list(1,R.num)R;
+% repositioning of the picture:
+ for i:=1 upto R.num: R[i]:=R[i] shifted -llxy; endfor
+ m*w'=xh_crd:=xh_crd-xl_crd; xl_crd:=0;
+ h'=yh_crd:=yh_crd-yl_crd; yl_crd:=0;
+% exporting:
+ write_preamble jobname;
+ clip_C make_list(1,R.num)R;
+ n:=0;
+ for i:=1 upto k-1: for j:=0 upto l-1:
+ n:=n+1;
+ fix_fill_cmyk
+ forsuffixes $=C,M,Y,K: (j/(l-1))[$[i],$[i+1]] if str$ <> "K": , fi endfor;
+ fill_C unitsquare xscaled 11/10w' yscaled h' shifted ((n-1)*w'-1/20w',0);
+ endfor endfor
+ write_postamble;
+endchar;
+end.
+%%\end
diff --git a/graphics/MF-PS/roex/roexsamp/roes-04.mf b/graphics/MF-PS/roex/roexsamp/roes-04.mf
new file mode 100644
index 0000000000..04585e9416
--- /dev/null
+++ b/graphics/MF-PS/roex/roexsamp/roes-04.mf
@@ -0,0 +1,91 @@
+%%%%
+%%%% This file belongs to the ROEX package.
+%%%%
+%%% draw find_BB fill_C fix_fill_cmyk write_preamble write_postamble
+%%% length cycle join
+%%% / //
+% ROES-04.MF, ``STAR FLOWERS'':
+% An example of removing overlaps of a single self-intersecting curve;
+% the sample curves (separate EPS files are generated for different
+% curves) are based upon a regular star polygon backbone;
+% the first curve is just such a polygon, the remaining two are
+% smooth variations (observe setting |epsil.time:=1/500| in the third case);
+% after removing overlaps objects are repositioned in such a way that
+% the lower left corner of the bounding box coincides with the origin
+% of coordinate system.
+%%%%
+%% % an innocent formatting trick: the underscore character ending a name
+%% % will be typeset as an superscript asterisk
+%% \let\oriunderscore\_
+%% \newif\ifbgroupopen\bgroupopenfalse
+%% \def\altdblbackslash#1{\bgroup\bgroupopentrue\it#1}
+%% \def\optegroup{\ifbgroupopen\egroup\fi}
+%% \def\underscoreasasterisk#1{%
+%% \ifx#1\relax\optegroup^*\else\oriunderscore#1\fi}
+%% \def\\#1{%
+%% \let\_\underscoreasasterisk
+%% \altdblbackslash{#1\relax}\optegroup
+%% \let\_\oriunderscore}
+% ---
+input mftoeps; eps_mode_setup; input roex; tracingremoving:=1;
+max_idx:=500; % better increase the default value
+% ---
+primarydef i // n =
+ (if n=0: 0 else: i/n fi) % why not to divide by 0?
+enddef;
+% ---
+h#=1in#; w#=1in#;
+% ---
+beginchar("0",w#,h#,0);
+ pickup pencircle scaled 1;
+ for case:=0,1,2:
+ path p, V[\\][\\]; pair R; save x,y; numeric N, K, A, twirl;
+ twirl:=180;
+% star polygons should fullfil |GCC(K,N)=1|, |1<K<N/2|
+% (|N| is the number of nodes, |K| is a `leap')
+ if case=0: % A
+ N=9; K=4; def join = -- enddef; twirl:=0;
+ elseif case=1: % B
+ N=7; K=2; def join = .. tension 3 .. enddef;
+ elseif case=2: % C
+ N=13; K=4; def join = .. tension 3 .. enddef; epsil.time:=1/500;
+ fi
+ A=180-(360/N)*K; R=1in*right; z0=origin;
+ for i:=1 upto N-1: z[i]=z[i-1]+R; R:=R rotated (180-A); endfor
+ p:=z0 for i:=1 upto N-1: join z[i] endfor join cycle;
+ if twirl<>0:
+ p:=z0{(direction 0 of p) rotated twirl}
+ for i:=1 upto N-1: join {(direction i of p) rotated twirl}z[i] endfor
+ join cycle;
+ fi
+ remove_overlap (p)()R; % dummy recombining
+ col_min:=infinity; col_max:=-infinity;
+ for i:=-EDGE_.num upto EDGE_.num: if i<>0:
+ col_min:=min(EDGE_.col[i],col_min); col_max:=max(EDGE_.col[i],col_max);
+ fi endfor;
+ find_BB p;
+ for k:=col_min upto col_max: if k<>0:
+ vardef good_colors(expr i,j) = (i=k) enddef;
+ message "recombine_edges: color=" & decimal(k);
+ recombine_edges(V[k]);
+ for l:=1 upto V[k]num: V[k][l]:=V[k][l] shifted -llxy; endfor
+ fi endfor;
+ xh_crd:=xh_crd-xl_crd; xl_crd:=0;
+ yh_crd:=yh_crd-yl_crd; yl_crd:=0;
+ write_preamble jobname & char(ASCII("a")+case);
+ for k:=col_min upto col_max: if k<>0:
+ if V[k]num>0:
+ if k>0:
+ fix_fill_cmyk 0,3/4(((k-1)//(col_max-1))**1/2)[1,0],1,0;
+ else:
+ fix_fill_cmyk 3/4(((1+k)//(1+col_min))**1/2)[1,0],1,0,0;
+ fi
+ fill_C make_list(1,V[k]num)V[k];
+ fi
+ fi endfor % |for k|
+ write_postamble;
+ endfor % |for case|
+endchar;
+% ---
+end.
+%%\end