diff options
Diffstat (limited to 'graphics/MF-PS')
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 |