Article View: comp.text.tex
Article #2387mfpic -- new version
From: Thomas Leathrum
Date: Tue, 08 Sep 1992 23:02
Date: Tue, 08 Sep 1992 23:02
2416 lines
62135 bytes
62135 bytes
This posting contains the latest version of mfpic, a
macro package for including pictures in TeX documents.
The idea behind this package is to have Metafont do the
actual drawing, and store the pictures in a font that TeX
can include in the document. The macros have been
designed so that the user should never have to learn
Metafont to use these macros -- the TeX macros actually
write the Metafont file for you.
The previous net release of this package was in late
June. There have been *MANY* changes since then. I
still don't view mfpic as being complete, but it is much
more so than the previous release, and most of the basic
features probably won't be changing any more.
mfpic has also started taking advantage of Metafont's
capabilites in a few more interesting ways. For example,
one of my personal favorite pieces of mfpic code looks
\picture[20]{-3}{3}{-3}{3}
\axes
\function{-2,2,0.1,(x**3-x)/3}
\endpicture
The first line opens up the picture environment and
establishes the coordinate system. The coorinate scale
is 20 points per coordinate unit (x- and y-axis scales
the same in this case), with bounds on both axes being -3
and 3. The second line draws the axes. The third line
plots a smooth Bezier interpolation of the function
f(x)=(x^3-x)/3 on the domain -2<=x<=2, through points
with x values 0.1 units apart. Since the algebraic
expression is passed directly to Metafont and parsed
there, the TeX user does not have to worry about
computing the points. The fourth line closes the picture
environment.
The files included below are as follows:
10288 graphbase.mf
265 lamfpic.tex
1307 lapictures.tex
6773 mfpic.tex
30473 mfpicdoc.tex
5469 objects.tex
1238 pictures.tex
The file mfpicdoc.tex contains documentation for all of
the mfpic macros. The files mfpic.tex and graphbase.tex
contain the actual macros. The file objects.tex is a
sample file containing at least one of every drawable
object. The file pictures.tex contains a few more
complicated pictures. The file lamfpic.tex is a header
file to allow LaTeX users to use mfpic without clashing
with the LaTeX picture environment. The file
lapictures.tex is the LaTeX version of the sample file
pictures.tex.
Much of the process of setting up your site to use mfpic
will be site-dependent. The biggest problem, no matter
where you are, will be convincing TeX and its output
drivers to find the Metafont output files. This often
involves modifying environment variables (or the
equivalent thereof) to inculde the current directory.
Coming in another posting: I have some scripts and
makefiles to facilitate setting up and processing TeX
files containing mfpic commands, for users on UNIX
machines. I will send those under separate cover.
Under development: I have recently gotten someone
interested in writing a fig-to-mfpic converter. I have
seen some preliminary code, and while it is still far
from complete, it is a step in the right direction.
If you find problems or bugs with the mfpic macros,
please e-mail me. I probably will not be able to help
much with site-dependent setup stuff, but I should be
able to answer questions about the actual macros.
Regards,
Tom Leathrum
moth@dartmouth.edu
-------------
%%%
%%% File: lamfpic.tex
%%%
\catcode`!=11
\let\!picture=\picture
\let\!endpicture=\endpicture
\input{mfpic}
\let\!pic=\picture
\let\!endpic=\endpicture
\newenvironment{mfpic}%
{\!pic}{\!endpic}
\let\picture=\!picture
\let\endpicture=\!endpicture
\catcode`!=12
%%%
%%% File: lapictures.tex
%%%
\documentstyle[12pt]{article}
\input{lamfpic}
\begin{document}
\opengraphsfile{lapics}
\noindent\begin{mfpic}[12]{0}{10}{0}{10}
\label[cc]{1}{9}{A}
\label[cc]{1}{1}{B}
\label[cc]{3}{5}{C}
\label[cc]{9}{9}{D}
\label[cc]{9}{1}{E}
\label[cc]{7}{5}{F}
\arrow{(1,8.5),(1,1.5)}
\arrow{(1.5,8.5),(2.5,5.5)}
\arrow{(2.5,4.5),(1.5,1.5)}
\arrow{(1.5,9),(8.5,9)}
\arrow{(9,8.5),(9,1.5)}
\arrow{(8.5,8.5),(7.5,5.5)}
\arrow{(7.5,4.5),(8.5,1.5)}
\arrow{(3.5,5),(6.5,5)}
\arrow{(1.5,1),(8.5,1)}
\caption{Commutative diagram example.}
\end{mfpic}
\noindent\begin{mfpic}[20]{-3}{3}{-3}{3}
\axes
\function{-2,2,0.1,((x**3)-x)/3}
\end{mfpic}
\noindent\begin{mfpic}[30]{-1}{1}{-1}{1}
\parafcn{0,6,0.1,(cosd(t*150)*cosd(t*90),cosd(t*150)*sind(t*90))}
\cdisk{(0,0),0.25}
\end{mfpic}
\noindent\begin{mfpic}[20]{-0.5}{4}{-0.5}{4}
\axes
\rect{(0,0),(1,0.5)}
\rectshade{(0,0),(1,0.5)}
\darkershade
\rect{(1,0),(2,1)}
\rectshade{(1,0),(2,1)}
\darkershade
\rect{(2,0),(3,2)}
\rectshade{(2,0),(3,2)}
\caption{A Bar Graph.}
\end{mfpic}
\noindent
\begin{mfpic}[30]{-1}{1.4}{-1}{1.1}
\linedir{(0,0),0,1}
\wedgefill{(0.3,0.2),0,60,1}
\linedir{(0,0),60,1}
\wedgeshade{(0,0),60,105,1}
\linedir{(0,0),105,1}
\arcth{(0,0),60,360,1}
\caption{A Pie Chart.}
\end{mfpic}
\closegraphsfile
\end{document}
%%%
%%% File: mfpic.tex
%%%
% preliminary version of macros
\catcode`@=11
\immediate\write16
{mfpic version 0.1.13.1 9/7/92}
% local declarations
\newwrite\@outx
\newbox\@labeledgraph
\newbox\@temp
\newdimen\@graphwd
\newdimen\@labeltemp
\newcount\@code
\newdimen\@centerskip
% dimension parameters
\newdimen\pointsize
\newdimen\shadespace
\newdimen\headlen
\newdimen\axisheadlen
\newdimen\hashlen
\newdimen\dashlen
\newdimen\dashspace
% default settings
\pointsize=2pt
\shadespace=1pt
\headlen=3pt
\axisheadlen=5pt
\hashlen=4pt
\dashlen=4pt
\dashspace=4pt
% standard setting macros
\def\darkershade{%
\multiply\shadespace by 5
\divide\shadespace by 6}
\def\lightershade{%
\multiply\shadespace by 6
\divide\shadespace by 5}
\def\dashlineset{%
\dashlen=4pt
\dashspace=4pt}
\def\dotlineset{%
\dashlen=1pt\
dashspace=2pt}
% direct output to Metafont file
\def\mfcmd#1{%
\immediate\write\@outx{#1}}
% pen size setting
\def\@pickup{%
\mfcmd{pickup pencircle scaled penwd;}}
\def\pen#1{%
\mfcmd{interim penwd:=#1;}
\@pickup}
% arrowhead shape setting
\def\headshape#1#2{
\mfcmd{interim hdwdr:=#1;
interim hdten:=#2;}}
% open and close file
\def\opengraphsfile#1{%
\@code32
\immediate\openout\@outx=#1.mf
\scrollmode
\font\@graph=#1
\errorstopmode
\immediate\write16
{Don't forget to process #1.mf!}
\immediate\write16
{Then reprocess this file.}
\mfcmd{mag:=\number\mag/1000; %
input graphbase.mf; code:=32;}
% set global defaults
\mfcmd{mfpicenv;}
\headshape{1}{1}
\pen{0.5pt}}
\def\closegraphsfile{%
\mfcmd{endmfpicenv;}
\mfcmd{end.}
\immediate\closeout\@outx}
% beginning picture environment
\def\@picture#1#2#3#4#5#6{%
% set up TeX
\global\font\@tcurr=\fontname\font
\relax\bgroup\nullfont
\global\advance\@code1
\global\@graphwd=#4pt
\global\advance\@graphwd by-#3pt
\global\multiply\@graphwd by#1
\global\setbox\@labeledgraph=
\vtop{\noindent\@graph\char\@code}
% set up Metafont file
\mfcmd{xscale:=#1; yscale:=#2; %
bounds(#3,#4,#5,#6);}
\mfcmd{beginchar(incr code,%
xscale*(xpos-xneg)*pt\#,%
yscale*(ypos-yneg)*pt\#,0);}
\mfcmd{setztr;}
\@pickup
% the macros
% points, lines, and arrows
\def\point##1{%
\mfcmd{pointd(##1,\the\pointsize);}}
\def\line##1{%
\mfcmd{line(##1);}}
\def\arrow##1{%
\mfcmd{arrow(##1,\the\headlen);}}
\def\dottedline##1{%
\mfcmd{dottedline(##1,\the\dashlen,%
\the\dashspace);}}
\def\dottedarrow##1{%
\mfcmd{dottedarrow(##1,\the\dashlen,%
\the\dashspace,\the\headlen);}}
% axes and axis marks
\def\axes{%
\mfcmd{axes(\the\axisheadlen);}}
\def\xmarks##1{%
\mfcmd{xmarks(\the\hashlen,##1);}}
\def\ymarks##1{%
\mfcmd{ymarks(\the\hashlen,##1);}}
% polygons
\def\rect##1{%
\mfcmd{rect(##1);}}
\def\dottedrect##1{%
\mfcmd{dottedrect(##1,%
\the\dashlen,\the\dashspace);}}
\def\block##1{%
\mfcmd{block(##1);}}
\def\rectshade##1{%
\mfcmd{rectshade(\the\shadespace,##1);}}
\def\polygon##1{
\mfcmd{curve(false,true,##1);}}
\def\polyshade##1{%
\mfcmd{cycleshade(\the\shadespace,%
false,##1);}}
\def\polyfill##1{%
\mfcmd{cycleshade(0,false,##1);}}
% circles and ellipses
\def\circle##1{%
\mfcmd{circle(##1);}}
\def\ellipse##1{%
\mfcmd{ellipse(##1,0);}}
\def\rotatedellipse##1{%
\mfcmd{ellipse(##1);}}
\def\circshade##1{%
\mfcmd{circshade(\the\shadespace,##1);}}
\def\ellshade##1{%
\mfcmd{ellshade(\the\shadespace,##1,0);}}
\def\rotatedellshade##1{%
\mfcmd{ellshade(\the\shadespace,##1);}}
\def\cdisk##1{%
\mfcmd{circshade(0,##1);}}
\def\edisk##1{%
\mfcmd{ellshade(0,##1,0);}}
\def\rotatededisk##1{%
\mfcmd{ellshade(0,##1);}}
% circular arcs
\def\arc##1{%
\mfcmd{arc(##1);}}
\def\arcarrow##1{%
\mfcmd{arcarrow(\the\headlen,##1);}}
\def\arcshade##1{%
\mfcmd{arcshade(\the\shadespace,##1);}}
\def\arcfill##1{%
\mfcmd{arcshade(0,##1);}}
% polar coordinates
\def\linedir##1{%
\mfcmd{linedir(##1);}}
\def\arrowdir##1{%
\mfcmd{arrowdir(\the\headlen,##1);}}
\def\arcth##1{%
\mfcmd{arcth(##1);}}
\def\arctharrow##1{%
\mfcmd{arctharrow(\the\headlen,##1);}}
\def\wedgeshade##1{%
\mfcmd{wedgeshade(\the\shadespace,##1);}}
\def\wedgefill##1{%
\mfcmd{wedgeshade(0,##1);}}
% curves
\def\curve##1{%
\mfcmd{curve(true,false,##1);}}
\def\polycurve##1{%
\mfcmd{curve(false,false,##1);}}
\def\curvedarrow##1{%
\mfcmd{curvedarrow(true,%
\the\headlen,##1);}}
\def\polyarrow##1{%
\mfcmd{curvedarrow(false,%
\the\headlen,##1);}}
% cyclic curves
\def\cyclic##1{%
\mfcmd{curve(true,true,##1);}}
\def\cycleshade##1{%
\mfcmd{cycleshade(\the\shadespace,%
true,##1);}}
\def\cyclefill##1{%
\mfcmd{cycleshade(0,true,##1);}}
% functions
\def\function##1{%
\mfcmd{function(true,##1);}}
\def\polyfunction##1{%
\mfcmd{function(false,##1);}}
\def\parafcn##1{%
\mfcmd{parafcn(true,##1);}}
\def\polyparafcn##1{%
\mfcmd{parafcn(false,##1);}}
\def\shadefcn##1##2##3{%
\mfcmd{shadefcn(\the\shadespace,##1)%
(##2)(##3);}}
% conversion (local)
\def\@xconv##1{%
\global\advance##1 by -#3pt
\global\multiply##1 by #1}
\def\@yconv##1{%
\global\advance##1 by -#5pt
\global\multiply##1 by -#2}
% labels and captions
\def\@label[##1##2]##3##4##5{%
% compute width of graph with label
% and reset size if necessary
\setbox\@temp=\hbox{\@tcurr##5}
\@labeltemp=##3pt
\@xconv\@labeltemp
\advance\@labeltemp by\wd\@temp
\ifdim\@labeltemp>\@graphwd
\global\@graphwd=\@labeltemp\fi
% set label onto picture
\global\setbox\@labeledgraph=
\vtop{\unvbox\@labeledgraph
\vbox to0pt{%
\if##1c\kern-0.5\ht\@temp\else
\if##1b\kern-\ht\@temp\fi\fi
\@labeltemp=##4pt
\@yconv\@labeltemp
\kern\@labeltemp
\hbox{\@labeltemp=##3pt
\@xconv\@labeltemp
\kern\@labeltemp
\if##2c\kern-0.5\wd\@temp\else
\if##2r\kern-\wd\@temp\fi\fi
\box\@temp}\vss}
\nointerlineskip}
} % -- end \label
\def\@labeldefault{\label[bl]}
\def\@dolabel{%
\if[\@nchr\expandafter\@label%
\else\expandafter\@labeldefault\fi}
\def\label{\futurelet\@nchr\@dolabel}
% called by \endpicture
\def\@docaption{}
\def\caption##1{%
% redefine to set caption
\def\@docaption{
% allow forced line breaks
\def\\{%
\global\font\@curr=\fontname\font
\relax\egroup\hbox\bgroup\@curr}
% compute adjustments to center
\setbox\@temp=\vbox{
\hbox\bgroup\@tcurr##1\egroup}
\ifdim\wd\@temp>\@graphwd
\global\@graphwd=\wd\@temp\fi
\@centerskip=\@graphwd
\advance\@centerskip -\wd\@temp
\divide\@centerskip by 2
% set caption onto picture
\global\setbox\@labeledgraph=
\vbox{\unvbox\@labeledgraph
\medskip\hbox{\noindent
\kern\@centerskip\box\@temp}\vss}}
} % -- end \caption
% end of object macros
} % -- end \@picture
% setting up optional arguments
\def\@piciii#1#2#3#4{%
\@picture{\@param}{\@param}%
{#1}{#2}{#3}{#4}}
\def\@picii[#1]#2#3#4#5{%
\@picture{\@param}{#1}{#2}{#3}{#4}{#5}}
\def\@pici{%
\if[\@nchr\expandafter\@picii
\else\expandafter\@piciii\fi}
\def\picture[#1]{%
\def\@param{#1}\futurelet\@nchr\@pici}
% ending picture environment
\def\endpicture{%
\mfcmd{endchar;}
\@docaption\egroup
\hbox to\@graphwd{%
\box\@labeledgraph\hss}
} % -- end endpicture
\catcode`@=12
%%%
%%% File: mfpicdoc.tex
%%%
\magnification=\magstep1
% heading macros
\newskip\myskip\myskip=5pt plus 1pt
\def\head#1{\vskip\myskip \noindent $\bullet$ {\it #1}
\par\nobreak}
\def\subhead#1{\vskip\myskip {\sl #1} \par\nobreak}
% abbreviations
\def\LaTeX{%
{\rm L\raise.42ex\hbox{\kern-.3em a}\kern-.15em\TeX}}
\def\PiCTeX{%
{\rm
P\kern-.12em\lower.5ex\hbox{I}\kern-.075emC%
\kern-.11em\TeX}}
\font\manual=logo10 % may want to use manfnt here instead
\def\MF{{\manual META}\-{\manual FONT}}
\def\PS{{\rm Post}\-{\rm Script}}
% metacode macros
\def\<{$\langle$\bgroup\it}\def\>{\egroup$\rangle$}
% macro to typeset macros
% e.g. \macro{name}[?arg1][arg2] gives
% \name[arg1]{arg2}
\def\gobble#1{}
\def\dooptparam[#1]{{\tt[#1]}\futurelet\nchr\domacro}
\def\dofixparam[#1]{{\tt\string{#1\string}}%
\futurelet\nchr\domacro}
\def\doparamswap{\if?\nchr%
\dooptparam[\expandafter\gobble\else\dofixparam[\fi}
\def\doparam{\futurelet\nchr\doparamswap}
\def\ddoparam{\expandafter\doparam\gobble}
\def\domacro{\if[\nchr\expandafter\ddoparam\fi}
\def\macro#1{{\tt\char\escapechar#1}%
\futurelet\nchr\domacro}
\centerline{\bf Pictures in \TeX\ with Metafont}
\head{Why?}
I got the idea for {\tt mfpic} mostly out of a feeling of
frustration. Different output mechanisms for printing or
viewing \TeX\ DVI files each have their own ways to
include pictures. More often than not, there are
provisions for including \PS\ data into a DVI file using
\TeX\ \macro{special}'s. However, this technique seems
far from \TeX's ideal of device-independence, and
besides, different \TeX\ output drivers handle these
\macro{special}'s in different ways. The same problems
arise with including {\tt tpic} \macro{special}'s.
\LaTeX's {\tt picture} environment has a hopelessly
limited supply of available objects to draw -- if you
want to draw a graph of a polynomial curve, you're out of
luck. There is, of course, \PiCTeX, which is wonderfully
flexible and general, but its most obvious feature is its
speed -- or rather lack of it. Processing a single
picture in \PiCTeX\ can often take several minutes. It
occured to me that it might be possible to take advantage
of the fact that \MF\ is {\it designed} for drawing
things. The result of pursuing this idea is {\tt mfpic},
a set of macros for \TeX\ and \MF\ which incorporate
Metafont-drawn pictures into a \TeX\ file. The nature of
the macros, from the user's point of view, is very much
like \PiCTeX. I do not pretend that {\tt mfpic} has
anything like the scope of \PiCTeX, but it should suit
most purposes for drawing small graphs and including them
in your \TeX\ documents.
\head{Author.}
{\tt mfpic} was written primarily by Tom Leathrum
(moth@dartmouth.edu) during the late spring and summer of
1992. Those who helped most in this process are credited
in the Acknowledgements.
\head{Manifest.}
There are seven files included in the {\tt mfpic}
distribution: {\tt mfpicdoc.tex} (this document, which
can be processed in plain \TeX), {\tt mfpic.tex} (the
\TeX\ macros), {\tt graphbase.mf} (the \MF\ macros),
{\tt objects.tex} (a sample file containing at least one
picture of each object), {\tt pictures.tex} (a short
sample file with a few more complicated pictures),
{\tt lamfpic.tex} (a short header file that sets up a
\LaTeX\ environment for pictures), and
{\tt lapictures.tex} (the \LaTeX\ version of
{\tt pictures.tex}). Information on how to set up a few
specific configurations of computers is also available,
separately.
\head{Setting Up and Processing.}
Setting up \TeX\ and \MF\ to process these files will, to
an extent, depend on your local installation. The
biggest problem you are likely to have, regardless of
your installation, will be convincing \TeX\ and its
output drivers to find \MF's output files.
To process the sample file, first run \TeX\ on the file
{\tt pictures.tex}. \TeX\ will complain that it can't
find the file {\tt pics.tfm}, but will continue
processing the file anyway. When the file is finished
processing, you will now have a file called
{\tt pics.mf}. This is the \MF\ file containing the
descriptions of the pictures for {\tt pictures.tex}. You
need to run \MF\ on {\tt pics.mf}, with
\macro{mode=localfont} set up. (Read your \MF\ manual to
see how to do this.) Now that you have the font and font
metric files generated by \MF, reprocess the file
{\tt pictures.tex} with \TeX. The resulting DVI file
should now be complete, and you should be able to print
and view it at your computer (assuming your viewer and
print driver have been set up to be able to find the font
generated by {\tt pics.mf}).
These three steps of processing -- processing with \TeX,
processing with \MF, and reprocessing with \TeX\ -- may
not always be necessary. In particular, if you change
the TeX document without making any changes at all to the
pictures, then there will be no need to repeat either of
the last two steps. There is also a somewhat subtle
circumstance under which you can skip the third step --
if you change the picture in such a way as {\it not} to
affect the font metric file, then you do not have to
reprocess with \TeX, because the original metric used for
the first step will put the pictures in the right places.
The only {\tt mfpic} macros that affect the font metric
file are the macros listed in the {\sl Files and
Environments} section below.
\head{How It Works.}
When you run \TeX\ on the file {\tt pictures.tex}, \TeX\
generates a file {\tt pics.mf}. This file is formed by
\macro{write} commands in the {\tt mfpic} macros. The
user should never have to read or change the file {\tt
pics.mf} directly -- the {\tt mfpic} macros take care of
it. The user familiar with \MF\ will notice, by looking
at the {\tt mfpic} macros, that the {\tt mfpic} drawing
macros translate almost directly into simple \MF\ {\tt
draw} commands. The \macro{label}'s and
\macro{caption}'s, however, are placed on the graph by
\TeX, not \MF.
\head{The Macros.}
\subhead{Files and Environments.}
\vskip\myskip
\noindent\macro{opengraphsfile}[\<font\>]$\dots$
\macro{closegraphsfile}
\nobreak
These macros open and close the Metafont file
which will contain the pictures to be included in this
document. The name of the file will be {\tt\<font\>.mf}.
If the \<font\> parameter is changed, you will have to
reprocess the \TeX\ file after processing
{\tt\<font\>.mf}.
\vskip\myskip
\noindent\macro{picture}[?\<xscale\>][?\<yscale\>]%
[\<xneg\>][\<xpos\>][\<yneg\>][\<ypos\>]
$\dots$\macro{endpicture}
\nobreak
These macros open and close the environment in
which the rest of the macros below make sense. The
\macro{picture} macro also sets up the local coordinate
system for the picture. The \<xscale\> and \<yscale\>
parameter establishes the length of a coordinate system
unit, in points. At least one scale parameter must be
specified, but if only one is specified, then they are
assumed to be equal. The \<xneg\> and \<xpos\>
parameters establish the lower and upper (resp.) bounds
for the $x$-axis coordinates; similarly, \<yneg\> and
\<ypos\> establish the bounds for the $y$-axis. These
bounds are expressed in local units -- in other words,
the actual width of the picture will be
\<xscale\>$\cdot$(\<xpos\>$-$\<xneg\>) points. These
scales and bounds are used primarily to establish the
metric for the character containing the picture described
within the environment. If any of these parameters are
changed, the {\tt\<font\>.tfm} file will be affected, so
you will have to reprocess the \TeX\ file after
processing {\tt\<font\>.mf}.
\vskip\myskip
The rest of the {\tt mfpic} macros do not
affect the font metric file ({\tt\<font\>.tfm}), and so
if these commands are changed or added in your document,
you will not have to repeat the third step of processing
(reprocessing with \TeX) to complete your \TeX\ document.
\vskip\myskip
For the remainder of the macros, the numerical parameters
are expressed in the units of the local coordinate system
specified by \macro{picture}, unless otherwise indicated.
\subhead{Points, Lines, Arrows, and Dotted Lines.}
\vskip\myskip
\noindent\macro{point}[(\<xval\>,\<yval\>)]
\nobreak
This macro draws a small filled circle centered
at the point {\tt (\<xval\>,\<yval\>)}. The diameter of
the circle is determined by the dimension
\macro{pointsize}. The default value of
\macro{pointsize} is 2 points.
\vskip\myskip
\noindent\macro{line}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>)]
\nobreak
This macro draws the line segment
with endpoints at the points
{\tt (\<xval0\>,\<yval0\>)} and
{\tt (\<xval1\>,\<yval1\>)}.
\vskip\myskip
\noindent\macro{arrow}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>)]
\nobreak
This macro draws an arrow starting from the point
{\tt (\<xval0\>,\<yval0\>)}
and pointing to the point {\tt (\<xval1\>,\<yval1\>)}.
The length of the arrowhead is determined by the
dimension \macro{headlen}. The default value of
\macro{headlen} is 3 points.
Each side of the arrowhead is a \MF\ Bezier curve
starting from the tip of the arrowhead and heading
initially parallel to the arrow line, then bending out to
the endpoint.
\vskip\myskip
\noindent\macro{dottedline}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>)]
\nobreak
This macro draws the dotted (or, more properly, dashed)
line segment specified as in the \macro{line} macro.
The length of the dashes is determined
by the dimension \macro{dashlen}. The default value of
\macro{dashlen} is 4 points. The space between the
dashes is determined by the dimension \macro{dashspace}.
The default value of \macro{dashspace} is 4 points. The
space between the dashes may be adjusted by as much as
${dashspace}\over{n}$, where $n$ is the number of spaces
appearing in the line segment, in order not to have
partial dashes at the ends.
\vskip\myskip
\noindent\macro{dottedarrow}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>)]
\nobreak
This macro draws a dotted arrow specified as in the
\macro{arrow} macro, with the
arrowhead the same
shape and size as in the \macro{arrow} command and the
dash length and spacing
determined as in the \macro{dottedline} macro.
\subhead{Axes and Axis Marks.}
\vskip\myskip
\noindent\macro{axes}
\nobreak
This macro draws the $x$ and $y$ axes for the coordinate
system. The length of the
arrowhead is determined by the
dimension \macro{axisheadlen}. The default value of
\macro{axisheadlen} is 5 points.
The shape of the arrowhead is determined as in the
{\tt\string\arrow} macro.
\vskip\myskip
\noindent\macro{xmarks}[\<value0\>,\<value1\>,$\dots$]
and
\macro{ymarks}[\<value0\>,\<value1\>,$\dots$]
\nobreak
These macros place hash marks on the $x$ and $y$ axes
(resp.) at the places indicated
by the values in the list. The
length of the hash marks is determined by the
dimension \macro{hashlen}. The default value of
\macro{hashlen} is
4 points.
\subhead{Polygons.}
\vskip\myskip
\noindent\macro{rect}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>)]
\nobreak
This macro draws the rectangle specified by the
given points {\tt (\<xval0\>,\<yval0\>)} and
{\tt (\<xval1\>,\<yval1\>)} being any two
opposite corners of the rectangle.
\vskip\myskip
\noindent\macro{dottedrect}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>)]
\nobreak
This macro draws the dotted line rectangle
specified as in the \macro{rect} macro.
The dash length and spacing are
determined as in the \macro{dottedline} macro.
\vskip\myskip
\noindent\macro{block}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>)]
\nobreak
This macro draws the filled rectangle
specified as in the \macro{rect} macro.
\vskip\myskip
\noindent\macro{rectshade}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>)]
\nobreak
This macro draws dots shading in the rectangle
specified as in the \macro{rect} macro.
This macro does {\it not} draw the
outline rectangle. The spacing between the dots is
determined by the
dimension \macro{shadespace}. The default value of
\macro{shadespace} is 1 point.
\vskip\myskip
\noindent\macro{polygon}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro draws a polygon with the specified points
at the vertices. The resulting
polygon can {\it not} be allowed to cross itself.
\vskip\myskip
\noindent\macro{polyshade}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro shades the region enclosed by the polygon specified as in the
\macro{polygon} macro. The spacing between dots is determined as in the
\macro{shaderect} macro.
\vskip\myskip
\noindent\macro{polyfill}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro fills the region enclosed by the polygon
specified as in the \macro{polygon} macro.
\subhead{Parameters.}
There are many parameters to {\tt mfpic} which the user
can modify to obtain different effects, such as different
arrowhead size or shape. Most of these parameters have
been described already in the context of macros they
modify, but they are all described together here. Most
of the parameters are stored by \TeX\ as dimensions, and
so are available globally, even if there is no \MF\ file
open; changes to them are subject to the usual \TeX\
rules of scope. Some parameters, however, are stored by
\MF, so the macros to change them will have no effect
unless a \MF\ file is open, and the changes are subject
to \MF's rules of scope -- to the {\tt mfpic} user, this
means that changes inside the \macro{picture} $\dots$
\macro{endpicture} environment are local to that
environment, but other \TeX\ groupings have no effect on
scope.
\vskip\myskip
\noindent\macro{pointsize}
\nobreak
This dimension stores the diameter of the filled circle
drawn by the \macro{point}
macro. The default value is 2 points.
\vskip\myskip
\noindent\macro{pen}[\<pensize\>]
\nobreak
This macro establishes the width of the drawing pen.
The default is 0.5 points.
This quantity is stored by \MF.
\vskip\myskip
\noindent\macro{headlen}
\nobreak
This dimension stores the length of the arrowhead
drawn by the \macro{arrow} macro.
The default value is 3 points.
\vskip\myskip
\noindent\macro{headshape}[\<hdwdr\>][\<hdten\>]
\nobreak
This macro establishes the shape of the arrowhead drawn
by the \macro{arrow} and \macro{axes} macros. The value
of \<hdwdr\> is the ratio of the width of the arrowhead
to its length, and \<hdten\> is the tension of the Bezier
curves. The default values are both 1. These values are
stored by \MF. Setting \macro{headshape}[1][infinity]
will make the sides of the arrowheads straight lines.
\vskip\myskip
\noindent\macro{dashlen}, \macro{dashspace}
\nobreak
These dimensions store, respectively, the length of
dashes and the length of spaces between dashes for lines
drawn by the \macro{dottedline} macro. The space between
the dashes may be adjusted by as much as
${dashspace}\over{n}$, where $n$ is the number of spaces
appearing in the line segment, in order not to have
partial dashes at the ends. The default values are both
4 points.
\vskip\myskip
\noindent\macro{dashlineset}, \macro{dotlineset}
\nobreak
These macros provide convenient standard settings for the
\macro{dashlen} and \macro{dashspace} dimensions. The
macro \macro{dashlineset} sets both values to 4 points;
the macro \macro{dotlineset} sets \macro{dashlen} to 1
point and \macro{dashspace} to 2 points.
\vskip\myskip
\noindent\macro{axisheadlen}
\nobreak
This dimension stores the length of the arrowhead
drawn by the \macro{axes} macro.
The default value is 5 points.
\vskip\myskip
\noindent\macro{hashlen}
\nobreak
This dimension stores the length of the axis
hash marks drawn by the \macro{xmarks}
and \macro{ymarks} macros. The default value is 4 points.
\vskip\myskip
\noindent\macro{shadespace}
\nobreak
This dimension establishes the spacing between dots
drawn by the \macro{rectshade}
macro. The default value is 1 point.
\vskip\myskip
\noindent\macro{darkershade}, \macro{lightershade}
\nobreak
These macros both multiply the \macro{shadespace}
dimension by constant factors,
$5\over6$ and $6\over5$ respectively, to provide
convenient standard settings for
several levels of shading.
\subhead{Circles, Ellipses, and Disks.}
\vskip\myskip
\noindent\macro{circle}[(\<xval\>,\<yval\>),\<rad\>]
\nobreak
This macro draws a circle centered at the
point {\tt (\<xval\>,\<yval\>)} and with radius \<rad\>.
\vskip\myskip
\noindent\macro{circshade}[(\<xval\>,\<yval\>),\<rad\>]
\nobreak
This macro draws a shaded circle, determined as in the
\macro{circle} macro. The spacing between dots is
determined as in the \macro{shaderect} macro.
\vskip\myskip
\noindent\macro{cdisk}[(\<xval\>,\<yval\>),\<rad\>]
\nobreak
This macro draws a filled circle, determined as in the
\macro{circle} macro.
\vskip\myskip
\noindent\macro{ellipse}[(\<xval\>,\<yval\>),%
\<xrad\>,\<yrad\>]
\nobreak
This macro draws an ellipse with the $x$ radius \<xrad\>
and $y$ radius \<yrad\>, centered at the point {\tt
(\<xval\>,\<yval\>)}.
\vskip\myskip
\noindent\macro{ellshade}[(\<xval\>,\<yval\>),%
\<xrad\>,\<yrad\>]
\nobreak
This macro draws a shaded ellipse, determined as in the
\macro{ellipse} macro. The spacing between dots is
determined as in the \macro{shaderect} macro.
\vskip\myskip
\noindent\macro{edisk}[(\<xval\>,\<yval\>),%
\<xrad\>,\<yrad\>]
\nobreak
This macro draws a filled ellipse, determined as in the
\macro{ellipse} macro.
\vskip\myskip
\noindent\macro{rotatedellipse}[(\<xval\>,\<yval\>),%
\<xrad\>,\<yrad\>,\<theta\>]
\nobreak
This macro draws an ellipse with the $x$ radius \<xrad\>
and $y$ radius \<yrad\> (before rotation), centered at
the point {\tt (\<xval\>,\<yval\>)}, and rotated around
its center by the angle \<theta\> (expressed in degrees).
\vskip\myskip
\noindent\macro{rotatedellshade}[(\<xval\>,\<yval\>),%
\<xrad\>,\<yrad\>,\<theta\>]
\nobreak
This macro draws a shaded ellipse, determined as in the
\macro{rotatedellipse} macro. The spacing between dots
is determined as in the \macro{shaderect} macro.
\vskip\myskip
\noindent\macro{rotatededisk}[(\<xval\>,\<yval\>),%
\<xrad\>,\<yrad\>,\<theta\>]
\nobreak
This macro draws a filled ellipse, determined as in the
\macro{rotatedellipse} macro.
\subhead{Circular Arcs.}
\vskip\myskip
\noindent\macro{arc}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),\<sweep\>]
\nobreak
This macro draws a circular arc starting from the point
{\tt (\<xval0\>,\<yval0\>)}, ending at the point
{\tt (\<xval1\>,\<yval1\>)}, and covering an arc angle of
\<sweep\> degrees, measured counterclockwise around the
center of the circle. If, for example, the points {\tt
(\<xval0\>,\<yval0\>)} and {\tt (\<xval1\>,\<yval1\>)}
lie on a horizontal line with {\tt (\<xval0\>,\<yval0\>)}
to the left, and \<sweep\> is between 0 and 180
(degrees), then the center of the circle will be above
the horizontal line (in order for the angle to be
counterclockwise). Negative values of \<sweep\> give
arcs curving in the other direction.
\vskip\myskip
\noindent\macro{arcarrow}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),\<sweep\>]
\nobreak
This marco draws an arc, specified as in the \macro{arc}
macro, with an arrowhead placed at the
{\tt (\<xval1\>,\<yval1\>)} end.
The shape and size of the
arrowhead are the same as in the \macro{arrow} macro.
\vskip\myskip
\noindent\macro{arcshade}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),\<sweep\>]
\nobreak
This macro shades the region enclosed by the arc,
specified as in the \macro{arc} macro, and the line
segment between {\tt (\<xval0\>,\<yval0\>)} and
{\tt (\<xval1\>,\<yval1\>)}. The spacing between dots is
determined as in the \macro{shaderect} macro.
\vskip\myskip
\noindent\macro{arcfill}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),\<sweep\>]
\nobreak
This macro fills the region specified as in the
\macro{arcshade} macro.
\subhead{Polar Coordinates.}
\vskip\myskip
\noindent\macro{linedir}[(\<xval\>,\<yval\>),%
\<theta\>,\<length\>]
\nobreak
This macro draws a line segment starting from the point
{\tt (\<xval\>,\<yval\>)} and going in the direction
specified by \<theta\>, where \<theta\> is an angle
measured in degrees counterclockwise from the direction
parallel to the positive $x$ axis, and with length
\<length\>.
\vskip\myskip
\noindent\macro{arrowdir}[(\<xval\>,\<yval\>),%
\<theta\>,\<length\>]
\nobreak
This macro draws an arrow starting from the point
{\tt (\<xval\>,\<yval\>)} and going in the
direction specified
by \<theta\>, where \<theta\> is an angle measured in
degrees counterclockwise from the direction parallel to
the positive $x$ axis, with length \<length\>, and with
an arrowhead at the end opposite the point {\tt
(\<xval\>,\<yval\>)}. The size and shape of the
arrowhead are determined as in the \macro{arrow} macro.
\vskip\myskip
\noindent\macro{arcth}[(\<xval\>,\<yval\>),%
\<theta1\>,\<theta2\>,\<rad\>]
\nobreak
This macro draws the arc with center at the point
{\tt (\<xval\>,\<yval\>)}, of radius \<rad\>,
from the angle
\<theta1\> to the angle \<theta2\>, where both angles are
measured in degrees counterclockwise from the direction
parallel to the $x$ axis.
\vskip\myskip
\noindent\macro{arctharrow}[(\<xval\>,\<yval\>),%
\<theta1\>,\<theta2\>,\<rad\>]
\nobreak
This macro draws an arc arrow, with the arc specified as
in the \macro{arcth} macro.
\vskip\myskip
\noindent\macro{wedgeshade}[(\<xval\>,\<yval\>),%
\<theta1\>,\<theta2\>,\<rad\>]
\nobreak
This macro shades the wedge-shaped region, from
the angle \<theta1\> to the angle \<theta2\> inside the
circle with center at the point {\tt (\<xval\>,\<yval\>)}
and radius \<rad\>, where both angles are measured in
degrees counterclockwise from the direction parallel to
the $x$ axis. The spacing between dots is determined as
in the \macro{shaderect} macro.
\vskip\myskip
\noindent\macro{wedgefill}[(\<xval\>,\<yval\>),%
\<theta1\>,\<theta2\>,\<rad\>]
\nobreak
This macro fills the wedge-shaped region specified
as in the \macro{wedgeshade} macro.
\subhead{Curves.}
\vskip\myskip
\noindent\macro{curve}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro draws a \MF\ Bezier path through the points
specified, in the order specified.
\vskip\myskip
\noindent\macro{polycurve}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro draws a polygonal path through the points
specified, in the order specified.
\vskip\myskip
\noindent\macro{curvedarrow}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro draws a \MF\ Bezier curve, specified as in the
\macro{curve} macro, then puts an arrowhead at the end.
The arrowhead is the same size and shape as the arrowhead
in the \macro{arrow} macro.
\vskip\myskip
\noindent\macro{polyarrow}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro draws a polygonal path, specified as in the
\macro{polycurve} macro, then puts an arrowhead at the
end. The arrowhead is the same size and shape as the
arrowhead in the \macro{arrow} macro.
\subhead{Cyclic Curves.}
\vskip\myskip
\noindent\macro{cyclic}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro draws a cyclic \MF\ Bezier curve through the
points specified. The curve can {\it not} be allowed to
cross itself.
\vskip\myskip
\noindent\macro{cycleshade}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro shades the region enclosed by the cyclic curve
specified as in the \macro{cyclic} macro. The spacing
between dots is determined as in the \macro{shaderect}
macro.
\vskip\myskip
\noindent\macro{cyclefill}[(\<xval0\>,\<yval0\>),%
(\<xval1\>,\<yval1\>),$\dots$]
\nobreak
This macro fills the region enclosed by the cyclic curve
specified as in the \macro{cyclic} macro.
\subhead{Functions.}
\vskip\myskip
\noindent\macro{function}[\<xmin\>,\<xmax\>,%
\<step\>,\<expr\>]
\nobreak
This macro plots the function determined by
$f(x)=$\<expr\>, where \<expr\> is written with the only
unknown being {\tt x}, using as $x$ values the points
starting with \<xmin\> and stepping by \<step\> until
reaching \<xmax\>. The function is interpolated with a
\MF\ Bezier path. The expression {\it expr} is passed
directly into the corresponding \MF\ macro and
interpreted there, so \MF's rules for algebraic
expressions apply. Operations available include {\tt +},
{\tt -}, {\tt *}, {\tt /}, and {\tt **}
({\tt x**y}$=x^y$), with {\tt(} and {\tt )} for grouping.
Functions available include {\tt round}, {\tt floor},
{\tt ceiling}, {\tt abs}, {\tt sqrt}, {\tt sind},
{\tt cosd}, {\tt mlog}, and {\tt mexp}. ({\it Notes:}
the trigonometric functions {\tt sind} and {\tt cosd}
take arguments in degrees; {\tt mlog(x)}$=256\ln x$, and
{\tt mexp} is its inverse. There are other operations
and functions available, but these are the most useful
for plotting purposes.) You can also define the function
$f(x)$ by cases using the Metafont conditional expression
{\tt if \<boolean\>: \<expr\> else: \<expr\> fi}.
Relations available for the \<boolean\> part of the
expression include {\tt =}, {\tt <}, {\tt >}, {\tt <=},
and {\tt >=}.
\vskip\myskip
\noindent\macro{polyfunction}[\<xmin\>,\<xmax\>,%
\<step\>,\<expr\>]
\nobreak
This macro plots the function determined by
$f(x)=$\<expr\>, as in the \noindent\macro{function}
macro, but using a polygonal path instead.
\vskip\myskip
\noindent\macro{parafcn}[\<tmin\>,\<tmax\>,\<step\>,%
(\<expr0\>,\<expr1\>)]
\nobreak
This macro plots the parametric path determined by
$(x(t),y(t))=${\tt (\<expr0\>,\<expr1\>)}, where
\<expr0\> and \<expr1\> are written with the only unknown
being {\tt t}, using as $t$ values the points starting
with \<tmin\> and stepping by \<step\> until reaching
\<tmax\>. The function is interpolated with a \MF\
Bezier path. The expressions \<expr0\> and \<expr1\>
are passed directly into the corresponding \MF\ macro, as
in the \macro{function} macro, so the same operations are
available.
\vskip\myskip
\noindent\macro{polyparafcn}[\<tmin\>,\<tmax\>,%
\<step\>,(\<expr0\>,\<expr1\>)]
\nobreak
This macro plots the parametric path specified as in the
\macro{parafcn} macro, but using a polygonal path instead.
\vskip\myskip
\noindent\macro{shadefcn}[\<xmin\>,\<xmax\>]%
[\<expr0\>][\<expr1\>]
\nobreak
This macro draws the shaded region between the two
functions $f(x)=$\<expr0\> and $g(x)=$\<expr1\>, where
\<expr0\> and \<expr1\> are written with the only unknown
being {\tt x}, bounded also by the vertical lines at
\<xmin\> and \<xmax\>. The functions $f$ and $g$ can
{\it not} be allowed to cross between \<xmin\> and
\<xmax\>. The expressions \<expr0\> and \<expr1\> are
passed directly into the corresponding \MF\ macro, as in
the \macro{function} macro, so the same operations are
available. The spacing between dots is determined as in
the \macro{shaderect} macro.
\subhead{Labels and Captions.}
\vskip\myskip
The next two macros do not affect the \MF\ file
({\tt\<font\>.mf}) at all, but are added to the picture
by \TeX. Therefore, if these macros are changed or added
in your document, there is no need to repeat either of
the last two steps (processing with \MF\ or reprocessing
with \TeX) in order to complete your \TeX\ document.
\vskip\myskip
\noindent\macro{label}[?\<orient\>][\<x\>][\<y\>]%
[\<label text\>]
\nobreak
This macro places a \TeX\ label on the graph. Without
the {\tt [\<orient\>]} parameter, the label is placed
with the lower left-hand corner of the label at the point
{\tt (\<x\>,\<y\>)}. Note the different format of the
point specification from the other {\tt mfpic} macros --
this is because \macro{label} does not use \MF\ to place
the label, but instead uses \TeX\ \macro{kern} commands.
The optional parameter {\tt [\<orient\>]} specifies the
relative placement of the label with respect to the point
{\tt (\<x\>,\<y\>)} -- \<orient\> is a two-character
sequence where the first character is one of {\tt t}
(top), {\tt c} (center), or {\tt b} (bottom), to specify
vertical placement, and the second character is one of
{tt l} (left), {\tt c} (center), or {\tt r} (right), to
specify horizontal placement. The default orientation is
equivalent to specifying {\tt [bl]}.
\vskip\myskip
\noindent\macro{caption}[\<x\>][\<y\>][\<caption text\>]
\nobreak
This macro places a caption at the bottom of the graph.
The caption text can also include the macro
{\tt\string\\}, which forces a line break in the caption.
\subhead{For Power Users Only.}
\vskip\myskip
\noindent\macro{mfcmd}[\<command text\>]
\nobreak
This macro writes the \<command text\> directly to the
Metafont file, using a \TeX\ \macro{write} command. This
can have some rather bizarre consequences, though, so
using it is not recommended.
\head{Using {\tt mfpic} with \LaTeX.}
For \LaTeX\ users, a short header file,
{\tt lamfpic.tex}, has been provided, which inputs
{\tt mfpic.tex} and uses the commands defined there to
set up a new \LaTeX\ environment called {\tt mfpic},
making sure in the process that the new environment does
not clash with the \LaTeX\ {\tt picture} environment. So
instead of using the {\tt\string\picture} and
\macro{endpicture} macros, you would use
\macro{begin}[mfpic] and \macro{end}[mfpic] A La\TeX\
version of the sample file, {\tt lapictures.tex}, has
also been provided. Note that the \macro{opengraphsfile}
and \macro{closegraphsfile} macros have {\it not} been
converted into a \LaTeX\ environment.
\head{Acknowledgements.}
I would like to thank all of the people here at Dartmouth
as well as out in the network world for testing {\tt
mfpic} and sending me back comments. I would
particularly like to thank Geoffrey Tobin
(ecsgrt@luxor.latrobe.edu.au) for his many suggestions,
especially about cleaning up the \MF\ code, enforcing
dimensions, fixing the dotted line computations, and
speeding up the shading routines (through this process,
Geoffrey and I managed to teach each other many of the
subtleties of \MF); and Bryan Green
(bgreen@sanjuan.uvic.ca) for his many suggestions, some
of which (including his rewriting the \macro{caption}
macro) ultimately led to the current version's ability to
put graphs in-line or side-by-side.
\head{Changes History.}
\noindent{\it Version 0.0.x:} Development versions.
Never released.
\par\noindent{\it Version 0.1:} First version released
to network, 6/30/1992.
\par\noindent{\it Version 0.1.x:} Test versions for new
features, fixes, etc.
None of them were released for general distribution.
Many new features added, bugs
worked out, code cleaned up.
\par\noindent{\it Version 0.2:} Second version released
to network, 9/7/1992.
\end
%%%
%%% File: objects.tex
%%%
\input mfpic
\magnification=\magstep1
\opengraphsfile{objs}
{\sl Points, Lines, and Arrows.}
\nobreak\noindent Point:
\picture[15]{0}{1}{0}{1}
\point{(0.5,0.5)}
\endpicture
\noindent Line segment:
\picture[15]{0}{2}{0}{1}
\line{(0,0.25),(2,0.75)}
\endpicture
\noindent Arrow:
\picture[15]{0}{2}{0}{1}
\arrow{(0,0.25),(2,0.75)}
\endpicture
\noindent Dotted line segment:
\picture[15]{0}{2}{0}{1}
\dottedline{(0,0.25),(2,0.75)}
\endpicture
\noindent Dotted arrow:
\picture[15]{0}{2}{0}{1}
\dottedarrow{(0,0.25),(2,0.75)}
\endpicture
\vskip5pt
{\sl Axes and Axis Marks.}
\nobreak\noindent Axes:
\noindent
\picture[15][20]{-2}{2}{-2}{2}
\axes
\endpicture
\noindent Axis marks:
\noindent
\picture[15][20]{-2}{2}{-2}{2}
\axes
\xmarks{-1,1}
\ymarks{-1,1}
\endpicture
\vskip5pt
{\sl Polygons.}
\nobreak\noindent Rectangle:
\picture[15]{0}{1}{0}{1}
\rect{(0,0),(0.8,1)}
\endpicture
\noindent Dotted rectangle:
\picture[20]{0}{1}{0}{1}
\dottedrect{(0,0),(0.8,1)}
\endpicture
\noindent Block:
\picture[15]{0}{1}{0}{1}
\block{(0,0),(0.8,1)}
\endpicture
\noindent Shaded rectangle:
\picture[15]{0}{1}{0}{1}
\rectshade{(0,0),(0.8,1)}
\endpicture
\noindent Polygon:
\picture[20]{0}{2}{0}{1}
\polygon{(0,0),(0,0.5),(1,1),(1.5,0.5),(1,0.5)}
\endpicture
\noindent Shaded polygon:
\picture[20]{0}{2}{0}{1}
\polyshade{(0,0),(0,0.5),(1,1),(1.5,0.5),(1,0.5)}
\endpicture
\noindent Filled polygon:
\picture[20]{0}{2}{0}{1}
\polyfill{(0,0),(0,0.5),(1,1),(1.5,0.5),(1,0.5)}
\endpicture
\vskip5pt
{\sl Circles and Ellipses.}
\nobreak\noindent Circle:
\picture[15]{0}{1}{0}{1}
\circle{(0.5,0.5),0.5}
\endpicture
\noindent Shaded circle:
\picture[15]{0}{1}{0}{1}
\circshade{(0.5,0.5),0.5}
\endpicture
\noindent Filled circle:
\picture[15]{0}{1}{0}{1}
\cdisk{(0.5,0.5),0.5}
\endpicture
\noindent Ellipse:
\picture[15]{0}{2}{0}{1}
\ellipse{(1,0.5),1,0.5}
\endpicture
\noindent Shaded ellipse:
\picture[15]{0}{2}{0}{1}
\ellshade{(1,0.5),1,0.5}
\endpicture
\noindent Filled ellipse:
\picture[15]{0}{2}{0}{1}
\edisk{(1,0.5),1,0.5}
\endpicture
\noindent Rotated ellipse:
\picture[15]{0}{2}{0}{1}
\rotatedellipse{(1,0.5),1,0.4,15}
\endpicture
\noindent Shaded rotated ellipse:
\picture[15]{0}{2}{0}{1}
\rotatedellshade{(1,0.5),1,0.4,15}
\endpicture
\noindent Filled rotated ellipse:
\picture[15]{0}{2}{0}{1}
\rotatededisk{(1,0.5),1,0.4,15}
\endpicture
\vskip5pt
{\sl Circular Arcs.}
\nobreak\noindent Circular arc:
\picture[15]{0}{2}{0}{1}
\arc{(0,0.8),(2,0.8),90}
\endpicture
\noindent Circular arc arrow:
\picture[15]{0}{2}{0}{1}
\arcarrow{(0,0.8),(2,0.8),90}
\endpicture
\noindent Shaded circular arc:
\picture[15]{0}{2}{0}{1}
\arcshade{(0,0.8),(2,0.8),90}
\endpicture
\noindent Filled circular arc:
\picture[15]{0}{2}{0}{1}
\arcfill{(0,0.8),(2,0.8),90}
\endpicture
\vskip5pt
{\sl Polar coordinates.}
\nobreak\noindent Line segment:
\picture[15]{0}{2}{0}{1}
\linedir{(0,0.2),20,2}
\endpicture
\noindent Arrow:
\picture[15]{0}{2}{0}{1}
\arrowdir{(0,0.2),20,2}
\endpicture
\noindent Circular arc:
\picture[15]{0}{1}{0}{1}
\arcth{(0,0),0,75,1}
\endpicture
\noindent Circular arc arrow:
\picture[15]{0}{1}{0}{1}
\arctharrow{(0,0),0,75,1}
\endpicture
\noindent Shaded wedge:
\picture[15]{0}{1}{0}{1}
\wedgeshade{(0,0),0,75,1}
\endpicture
\noindent Filled wedge:
\picture[15]{0}{1}{0}{1}
\wedgefill{(0,0),0,75,1}
\endpicture
\vskip5pt
{\sl Curves.}
\nobreak\noindent Curve:
\picture[15]{0}{2}{0}{1}
\curve{(0,0.25), (1,0.75), (1,0.25), (2,0.75)}
\endpicture
\noindent Polygonal curve:
\picture[15]{0}{2}{0}{1}
\polycurve{(0,0.25), (1,0.75), (1,0.25), (2,0.75)}
\endpicture
\noindent Curved arrow:
\picture[15]{0}{2}{0}{1}
\curvedarrow{(0,0.25), (1,0.75), (1,0.25), (2,0.75)}
\endpicture
\noindent Polygonal curve arrow:
\picture[15]{0}{2}{0}{1}
\polyarrow{(0,0.25), (1,0.75), (1,0.25), (2,0.75)}
\endpicture
\vskip5pt
{\sl Cyclic Curves.}
\nobreak\noindent Cyclic curve:
\picture[20]{0}{2}{0}{1}
\cyclic{(0.5,0),(0,0.3),(0.5,0.8),(1.5,0.8),(2.0,0.3),(1.5,0),(1.0,0.3)}
\endpicture
\noindent Shaded cyclic curve:
\picture[20]{0}{2}{0}{1}
\cycleshade{(0.5,0),(0,0.3),(0.5,0.8),(1.5,0.8),(2.0,0.3),(1.5,0),(1.0,0.3)}
\endpicture
\noindent Filled cyclic curve:
\picture[20]{0}{2}{0}{1}
\cyclefill{(0.5,0),(0,0.3),(0.5,0.8),(1.5,0.8),(2.0,0.3),(1.5,0),(1.0,0.3)}
\endpicture
\vskip5pt
{\sl Functions.}
\nobreak\noindent Function plot:
\picture[20]{0}{1}{0}{1}
\function{0,1,0.125,sind(x*180)}
\endpicture
\noindent Polygonal function plot:
\picture[20]{0}{1}{0}{1}
\polyfunction{0,1,0.125,sind(x*180)}
\endpicture
\noindent Parametric function plot:
\picture[20]{0}{1}{0}{1}
\parafcn{0,1,0.125,(sind(180*t)*cosd(90*t),sind(180*t)*sind(90*t))}
\endpicture
\noindent Polygonal parametric function plot:
\picture[20]{0}{1}{0}{1}
\polyparafcn{0,1,0.125,(sind(180*t)*cosd(90*t),sind(180*t)*sind(90*t))}
\endpicture
\noindent Shading between functions:
\picture[20]{0}{1}{0}{1}
\shadefcn{0,0.7}{x**2}{sind(x*180)}
\endpicture
\vskip5pt
{\sl Labels and Captions.}
\nobreak\noindent Label:
\noindent
\picture[20]{-1}{1}{-1}{1}
\circle{(0,0),1}
\point{(0,0)}
\point{(0.333,0.333)}
\point{(-0.333,0.333)}
\arc{(-0.333,-0.333),(0.333,-0.333),60}
\arrow{(1,0.5),(0.1,0)}
\label{1}{0.5}{nose}
\endpicture
\noindent Caption:
\noindent
\picture[20]{-1}{1}{-1}{1}
\circle{(0,0),1}
\point{(0,0)}
\point{(0.333,0.333)}
\point{(-0.333,0.333)}
\arc{(-0.333,-0.333),(0.333,-0.333),60}
\caption{Smile!}
\endpicture
\closegraphsfile
\end
%%%
%%% File: pictures.tex
%%%
\input mfpic
\magnification=\magstep1
\opengraphsfile{pics}
\noindent
\picture[12]{0}{10}{0}{10}
\label[cc]{1}{9}{A}
\label[cc]{1}{1}{B}
\label[cc]{3}{5}{C}
\label[cc]{9}{9}{D}
\label[cc]{9}{1}{E}
\label[cc]{7}{5}{F}
\arrow{(1,8.5),(1,1.5)}
\arrow{(1.5,8.5),(2.5,5.5)}
\arrow{(2.5,4.5),(1.5,1.5)}
\arrow{(1.5,9),(8.5,9)}
\arrow{(9,8.5),(9,1.5)}
\arrow{(8.5,8.5),(7.5,5.5)}
\arrow{(7.5,4.5),(8.5,1.5)}
\arrow{(3.5,5),(6.5,5)}
\arrow{(1.5,1),(8.5,1)}
\caption{Commutative diagram example.}
\endpicture
\noindent
\picture[20]{-3}{3}{-3}{3}
\axes
\function{-2,2,0.1,((x**3)-x)/3}
\endpicture
\noindent
\picture[30]{-1}{1}{-1}{1}
\parafcn{0,6,0.1,
(cosd(t*150)*cosd(t*90),
cosd(t*150)*sind(t*90))}
\cdisk{(0,0),0.25}
\endpicture
\noindent
\picture[20]{-0.5}{4}{-0.5}{4}
\axes
\rect{(0,0),(1,0.5)}
\rectshade{(0,0),(1,0.5)}
\darkershade
\rect{(1,0),(2,1)}
\rectshade{(1,0),(2,1)}
\darkershade
\rect{(2,0),(3,2)}
\rectshade{(2,0),(3,2)}
\caption{A Bar Graph.}
\endpicture
\picture[30]{-1}{1.4}{-1}{1.1}
\linedir{(0,0),0,1}
\wedgefill{(0.3,0.2),0,60,1}
\linedir{(0,0),60,1}
\wedgeshade{(0,0),60,105,1}
\linedir{(0,0),105,1}
\arcth{(0,0),60,360,1}
\caption{A Pie Chart.}
\endpicture
\closegraphsfile
\end
%%%
%%% File: graphbase.mf
%%%
mode_setup;
message "mfpic version 0.1.13.1 9/7/92";
%set up local environment
def mfpicenv =
begingroup
% miscellaneous utilities
save floorpair;
vardef floorpair(expr p) =
(floor (xpart p), floor (ypart p))
enddef;
save ceilingpair;
vardef ceilingpair(expr p) =
(ceiling (xpart p), ceiling (ypart p))
enddef;
save minpair, p,x,y;
vardef minpair(expr u)(text t) =
pair p; numeric x, y;
p:=u;
for q=t:
x:=min(xpart p, xpart q);
y:=min(ypart p, ypart q);
p:=(x,y);
endfor;
p
enddef;
save maxpair, p,x,y;
vardef maxpair(expr u)(text t) =
pair p; numeric x, y;
p:=u;
for q=t:
x:=max(xpart p, xpart q);
y:=max(ypart p, ypart q);
p:=(x,y);
endfor;
p
enddef;
% setup
save bounds,
xneg,xpos,yneg,ypos;
def bounds(expr a,b,c,d) =
xneg:=a;
xpos:=b;
yneg:=c;
ypos:=d;
enddef;
% conversion
save xconv;
def xconv(expr xvalue) =
((xvalue-xneg)/(xpos-xneg))*w
enddef;
save unxconv;
def unxconv(expr pvalue) =
((pvalue/w)*(xpos-xneg)+xneg)
enddef;
save yconv;
def yconv(expr yvalue) =
((yvalue-yneg)/(ypos-yneg))*h
enddef;
save ztr;
transform ztr;
save setztr;
def setztr =
ztr:=identity
shifted -(xneg,yneg)
xscaled (w/(xpos-xneg))
yscaled (h/(ypos-yneg));
enddef;
% pen width
% in pixel coordinates
save penwd;
newinternal penwd;
% arrowheads
% in pixel coordinates
save hdwdr, hdten;
newinternal hdwdr, hdten;
save head, p,side;
def head(expr front, back, width, t) =
pair p[], side;
side := (width/2) *
((front-back) rotated 90);
p1 := back + side;
p2 := back - side;
draw front{back-front}..tension t..p1;
draw front{back-front}..tension t..p2;
enddef;
save headpath, p;
def headpath(expr f,hlen)=
pair p[];
p2:=point infinity of f;
p1:=direction infinity of f;
if p1<>(0,0):
head(p2,p2-(hlen*unitvector(p1)),
hdwdr,hdten);
fi;
enddef;
% shading routine
% in pixel coordinates
save onedot;
def onedot(expr p)(suffix v) =
addto v doublepath p
withpen currentpen;
enddef;
save clip;
vardef clip(expr f)(suffix v) =
save vt;
picture vt;
vt:=v;
cull vt keeping (1,infinity);
addto vt contour f;
cull vt keeping (2,infinity);
vt
enddef;
save shadepath, v,p,ll,ur,
mn,m,n,twosp;
def shadepath(expr sp,f) =
picture v;
pair p[], ll, ur, mn;
if not cycle f: ;
elseif sp<=0: fill f;
else:
ur:=ll:=point 0 of f;
for i:=0 upto length f:
p0:=point i of f;
p1:=precontrol i of f;
p2:=postcontrol i of f;
ll:=minpair(ll, p0, p1, p2);
ur:=maxpair(ur, p0, p1, p2);
endfor;
ll:=sp*(ceilingpair(ll/sp));
mn:=floorpair((ur-ll)/sp);
m:=xpart mn;
n:=ypart mn;
twosp:=2*sp;
v:=nullpicture;
p2:=ll;
for i:=0 upto m:
p3:=p2 if odd i: +(0,sp) fi;
for j:=0 upto n:
if (not odd (i+j)):
onedot(p3,v);
p3:=p3+(0,twosp);
fi;
endfor;
p2:=p2+(sp,0);
endfor;
addto currentpicture
also clip(f,v);
fi;
enddef;
% * rest of macros start in graphing
% coordinates but convert to pixel
% to draw
% * variables ending in ".px"
% converted to pixel
% * exceptions are the TeX dimensions
% here called:
% ptwd, hlen, dlen, slen, len, sp
% all of which are in pixel coordinates
% * macros beginning with "mk" operate
% entirely in graphing coordinates
% general path construction
save mkpath;
def mkpath(expr smooth, cyclic, n)
(suffix pts) =
if smooth:
if cyclic:
pts[1]{pts[2]-pts[n]}
else:
pts[1]
fi
for i:=2 upto n-1:
..pts[i]{pts[i+1]-pts[i-1]}
endfor
if cyclic:
..pts[n]{pts[1]-pts[n-1]}..cycle
else:
..pts[n]
fi
else:
for i:=1 upto n-1:
pts[i] --
endfor
pts[n]
if cyclic:
-- cycle
fi
fi
enddef;
% points, lines, and arrows
save pointd, p;
def pointd(expr a,ptwd) =
pair p.px;
p.px:=a transformed ztr;
fill fullcircle scaled ptwd shifted p.px;
enddef;
save line;
def line(expr a,b) =
draw (a..b) transformed ztr;
enddef;
save arrow, f;
def arrow(expr tl,hd,hlen) =
path f.px;
f.px:= (tl..hd) transformed ztr;
draw f.px;
headpath(f.px,hlen);
enddef;
save dottedline, p,
v,l,delta,n;
def dottedline(expr a,b,dlen,slen) =
pair p.px[];
pair v.px;
p.px1:=a transformed ztr;
p.px3:=b transformed ztr;
l.px:=length(p.px3-p.px1);
if (l.px<=2*dlen) or
(dlen<0) or (slen<0):
draw p.px1..p.px3;
else:
v.px:=unitvector(p.px3-p.px1);
n:=floor((l.px+slen-dlen)/(dlen+slen));
delta:=((l.px-dlen)/n)-(dlen+slen);
for i:=1 upto n:
p.px2:=p.px1+(dlen*v.px);
draw p.px1..p.px2;
p.px1:=p.px2+((slen+delta)*v.px);
endfor;
draw p.px1..p.px3;
fi;
enddef;
save dottedarrow;
def dottedarrow(expr tl,hd,dlen,
slen,hlen) =
dottedline(tl,hd,dlen,slen);
headpath((tl..hd) transformed ztr,hlen);
enddef;
% axes and axis marks
save axes;
def axes(expr hlen) =
arrow((0,yneg),(0,ypos),hlen);
arrow((xneg,0),(xpos,0),hlen);
enddef;
save xmarks;
def xmarks(expr len)(text t) =
for a=t:
draw (xconv(a),yconv(0)-(len/2))..
(xconv(a),yconv(0)+(len/2));
endfor;
enddef;
save ymarks;
def ymarks(expr len)(text t) =
for a=t:
draw (xconv(0)-(len/2),yconv(a))..
(xconv(0)+(len/2),yconv(a));
endfor;
enddef;
% polygons
save mkrect;
def mkrect(expr ll,ur) =
ll--(xpart ll,ypart ur)--
ur--(xpart ur,ypart ll)--cycle
enddef;
save rect;
def rect(expr ll,ur) =
draw (mkrect(ll,ur)) transformed ztr;
enddef;
save dottedrect;
def dottedrect(expr ll,ur,dlen,slen) =
dottedline(ll,(xpart ll,ypart ur),
dlen,slen);
dottedline((xpart ll,ypart ur),ur,
dlen,slen);
dottedline(ur,(xpart ur,ypart ll),
dlen,slen);
dottedline((xpart ur,ypart ll),ll,
dlen,slen);
enddef;
save block;
def block(expr ll,ur) =
fill (mkrect(ll,ur)) transformed ztr;
enddef;
save rectshade;
def rectshade(expr sp,ll,ur) =
path f.px;
f.px:=(mkrect(ll,ur)) transformed ztr;
shadepath(sp,f.px);
enddef;
% circles and ellipses
save mkellipse;
vardef mkellipse(expr center,radx,rady,
angle) =
save t;
transform t;
t:=identity xscaled (2*radx)
yscaled (2*rady) rotated angle
shifted center;
fullcircle transformed t
enddef;
save ellipse;
def ellipse(expr center,radx,rady,
angle) =
draw
(mkellipse(center,radx,rady,angle))
transformed ztr;
enddef;
save circle;
def circle(expr center,rad) =
ellipse(center,rad,rad,0);
enddef;
save ellshade ,f;
def ellshade (expr sp, center,
radx, rady, angle) =
path f.px;
f.px:=
(mkellipse(center,radx,rady,angle))
transformed ztr;
shadepath(sp,f.px);
enddef;
save circshade;
def circshade(expr sp, center,rad) =
ellshade(sp,center,rad,rad,0);
enddef;
% circular arcs
save mkarc;
vardef mkarc(expr center,from,sweep)=
save p,f,n,i;
pair p[];
path f;
if sweep=0: f:=from;
else:
n:=floor(abs(sweep)/45)+1;
if n<3: n:=3; fi;
theta:=sweep/(n-1);
p1:=from;
for i:=2 upto n:
p[i]:=p[i-1]
rotatedabout (center,theta);
endfor;
f:=mkpath(true,false,n,p)
fi;
f
enddef;
save arccenter;
vardef arccenter(expr from,to,sweep)=
save midpt, disp;
pair midpt;
midpt:=(0.5)[from,to];
disp:=
if ((sweep mod 360)=0):
0
else:
cosd(sweep/2)/sind(sweep/2)
fi;
midpt+(disp*((to-from) rotated 90)/2)
enddef;
save arc, center;
def arc(expr from,to,sweep) =
pair center;
center:=arccenter(from,to,sweep);
draw (mkarc(center, from, sweep))
transformed ztr;
enddef;
save arcarrow, center,f;
def arcarrow(expr hlen,from,to,sweep) =
pair center;
path f.px;
center:=arccenter(from,to,sweep);
f.px:=(mkarc(center, from, sweep))
transformed ztr;
draw f.px;
headpath(f.px,hlen);
enddef;
save arcshade, center,f;
def arcshade(expr sp,from,to,sweep) =
pair center;
path f.px;
center:=arccenter(from,to,sweep);
f.px:=(mkarc(center,from,sweep)--cycle)
transformed ztr;
shadepath(sp,f.px);
enddef;
% modified polar coordinates
save linedir, p;
def linedir(expr a,theta,len) =
pair p;
p:=a+len*(dir theta);
draw (a..p) transformed ztr;
enddef;
save arrowdir, p,f;
def arrowdir(expr hlen,a,theta,len) =
pair p;
path f.px;
p:=a+len*(dir theta);
f.px:= (a..p) transformed ztr;
draw f.px;
headpath(f.px,hlen);
enddef;
save arcth, from;
def arcth(expr center,
frtheta,totheta,rad) =
pair from;
from:=center+rad*(dir frtheta);
draw (mkarc(center,from,
totheta-frtheta))
transformed ztr;
enddef;
save arctharrow, from,f;
def arctharrow(expr hlen,center,
frtheta,totheta,rad) =
pair from;
path f.px;
from:=center+rad*(dir frtheta);
f.px:= (mkarc(center,from,
totheta-frtheta))
transformed ztr;
draw f.px;
headpath(f.px,hlen);
enddef;
save wedgeshade, from,f;
def wedgeshade(expr sp,center,
frtheta,totheta,rad) =
pair from;
path f.px;
from:=center+rad*(dir frtheta);
f.px:=(center--
mkarc(center,from,totheta-frtheta)
--cycle) transformed ztr;
shadepath(sp, f.px);
enddef;
% curves
save mkcurve;
vardef mkcurve(expr smooth,cyclic)
(text t)=
save i,p,a;
i:=0;
pair p[];
for a=t:
p[incr i]:=a;
endfor;
mkpath(smooth,cyclic,i,p)
enddef;
save curve;
def curve(expr smooth,cyclic)
(text t) =
draw (mkcurve(smooth,cyclic,t))
transformed ztr;
enddef;
save curvedarrow, f;
def curvedarrow(expr smooth,hlen)
(text t) =
path f.px;
f.px:=(mkcurve(smooth,false,t))
transformed ztr;
draw f.px;
headpath(f.px,hlen);
enddef;
% cyclic curves
save cycleshade, f;
def cycleshade(expr sp,smooth)(text t) =
path f.px;
f.px:=mkcurve(smooth,true,t)
transformed ztr;
shadepath(sp,f.px);
enddef;
% functions
save mkfcn;
vardef mkfcn(expr smooth,bmin,bmax,bst)
(suffix bv)(text fcnpr)=
save p,i;
pair p[];
i:=0;
for bv:=bmin step bst
until bmax+(bst/2):
p[incr i]:=fcnpr;
endfor;
mkpath(smooth,false,i,p)
enddef;
save function;
def function(expr smooth,xmin,xmax,st)
(text fx) =
draw (mkfcn(smooth,xmin,xmax,st,
x,(x,fx)))
transformed ztr;
enddef;
save parafcn;
def parafcn(expr smooth,tmin,tmax,st)
(text ft) =
draw (mkfcn(smooth,tmin,tmax,st,
t,ft))
transformed ztr;
enddef;
save shadefcn, f,st;
def shadefcn(expr sp, xmin, xmax)
(text fcni)(text fcnii) =
path f.px;
st:=unxconv(sp);
f.px:=(mkfcn(false,xmin,xmax,st,
x,(x,fcni))
--reverse
mkfcn(false,xmin,xmax,st,
x,(x,fcnii))
--cycle) transformed ztr;
shadepath(sp,f.px);
enddef;
enddef; % mfpicenv
def endmfpicenv =
endgroup;
enddef;
Technical Details
Message-ID:
<1992Sep8.230254.9504@dartvax.dartmouth.edu>Path:
arc1-ca.pugleaf.net!sparky!uunet!zaphod.mps.ohio-state.edu!rpi!bu.edu!dartvax!griggs.dartmouth.edu!leathrumShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!zaphod.mps.ohio-state.edu!rpi!bu.edu!dartvax!griggs.dartmouth.edu!leathrum From: leathrum@griggs.dartmouth.edu (Thomas Leathrum) Newsgroups: comp.text.tex Subject: mfpic -- new version Message-ID: <1992Sep8.230254.9504@dartvax.dartmouth.edu> Date: 8 Sep 92 23:02:54 GMT Sender: news@dartvax.dartmouth.edu (The News Manager) Reply-To: leathrum@griggs.dartmouth.edu (Thomas Leathrum) Followup-To: comp.text.tex Organization: Dept. of Math and Computer Science, Dartmouth College Lines: 2416